robchang commited on
Commit
e27fcda
·
1 Parent(s): 2a33144

Deploy KLH10 TOPS-20 emulator

Browse files
build/wasm/bld-kl/index.html CHANGED
@@ -195,11 +195,51 @@
195
  .vt100-screen::before { display: none; }
196
  }
197
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
198
  /* Boot overlay */
199
  .boot-overlay {
200
  position: absolute;
201
  top: 0; left: 0; right: 0; bottom: 0;
202
- background: rgba(0, 0, 0, 0.75);
203
  display: flex;
204
  align-items: center;
205
  justify-content: center;
@@ -258,8 +298,22 @@
258
  <div id="terminal"></div>
259
  </div>
260
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
261
  <div class="mode-toggle" style="text-align: center; margin-bottom: 16px;">
262
  <a href="#" id="toggleFrame">Hide Terminal Frame</a>
 
 
263
  </div>
264
 
265
  <div style="text-align: center; font-size: 13px; color: #999; margin-top: 20px;">
 
195
  .vt100-screen::before { display: none; }
196
  }
197
 
198
+ /* ============================================
199
+ Special Key Toolbar (mobile + optional desktop)
200
+ ============================================ */
201
+ .key-toolbar {
202
+ display: none;
203
+ gap: 6px;
204
+ padding: 8px 4px;
205
+ justify-content: center;
206
+ flex-wrap: wrap;
207
+ max-width: 1400px;
208
+ margin: 0 auto;
209
+ }
210
+ .key-toolbar button {
211
+ font-family: 'Consolas', 'Courier New', monospace;
212
+ font-size: 14px;
213
+ color: #4fc3f7;
214
+ background: #333;
215
+ border: 1px solid #555;
216
+ border-radius: 6px;
217
+ min-width: 44px;
218
+ height: 44px;
219
+ padding: 0 10px;
220
+ cursor: pointer;
221
+ touch-action: manipulation;
222
+ -webkit-tap-highlight-color: transparent;
223
+ user-select: none;
224
+ }
225
+ .key-toolbar button:active {
226
+ background: #4fc3f7;
227
+ color: #000;
228
+ }
229
+ .key-toolbar .key-ctrl.active {
230
+ background: #4fc3f7;
231
+ color: #000;
232
+ border-color: #4fc3f7;
233
+ }
234
+ @media (max-width: 600px) {
235
+ .key-toolbar { display: flex; }
236
+ }
237
+
238
  /* Boot overlay */
239
  .boot-overlay {
240
  position: absolute;
241
  top: 0; left: 0; right: 0; bottom: 0;
242
+ background: rgba(0, 0, 0, 0.35);
243
  display: flex;
244
  align-items: center;
245
  justify-content: center;
 
298
  <div id="terminal"></div>
299
  </div>
300
  </div>
301
+ <div class="key-toolbar" id="keyToolbar">
302
+ <button data-key="esc">Esc</button>
303
+ <button data-key="tab">Tab</button>
304
+ <button data-key="ctrl" class="key-ctrl">Ctrl</button>
305
+ <button data-key="up">&#x2191;</button>
306
+ <button data-key="down">&#x2193;</button>
307
+ <button data-key="left">&#x2190;</button>
308
+ <button data-key="right">&#x2192;</button>
309
+ <button data-key="ctrl-c">^C</button>
310
+ <button data-key="ctrl-z">^Z</button>
311
+ <button data-key="ctrl-d">^D</button>
312
+ </div>
313
  <div class="mode-toggle" style="text-align: center; margin-bottom: 16px;">
314
  <a href="#" id="toggleFrame">Hide Terminal Frame</a>
315
+ &nbsp;&middot;&nbsp;
316
+ <a href="#" id="toggleKeybar">Show Key Toolbar</a>
317
  </div>
318
 
319
  <div style="text-align: center; font-size: 13px; color: #999; margin-top: 20px;">
build/wasm/bld-kl/main.js CHANGED
@@ -108,6 +108,14 @@ class KLH10WebInterface {
108
  this.terminal.onData((data) => {
109
  if (this.autoBootInProgress) return; // Block input during auto-boot
110
  if (this.worker && this.emulatorReady && this.inputRingBuffer) {
 
 
 
 
 
 
 
 
111
  // Echo input based on both mode and echo setting
112
  if (this.inRuncmdMode && this.terminalEchoEnabled) {
113
  // Handle special characters
@@ -121,20 +129,8 @@ class KLH10WebInterface {
121
  this.terminal.write(data);
122
  }
123
  }
124
-
125
- // Write directly to WASM memory ring buffer - true zero-copy!
126
-
127
-
128
- for (let i = 0; i < data.length; i++) {
129
- const char = data[i];
130
- const success = this.inputRingBuffer.writeInputChar(char);
131
-
132
-
133
- if (!success) {
134
- console.warn('Main: Input ring buffer full, character dropped');
135
- break;
136
- }
137
- }
138
  }
139
  });
140
 
@@ -186,13 +182,25 @@ class KLH10WebInterface {
186
  // Cell dimensions are approximately: width ~ fontSize * 0.6, height ~ fontSize * 1.2
187
  const maxByWidth = screenWidth / (80 * 0.6);
188
  const maxByHeight = screenHeight / (24 * 1.2);
189
- const fontSize = Math.max(8, Math.min(Math.floor(Math.min(maxByWidth, maxByHeight)), 20));
190
 
191
  this.terminal.options.fontSize = fontSize;
192
  this.fitAddon.fit();
193
  this.terminal.resize(80, 24);
194
  }
195
 
 
 
 
 
 
 
 
 
 
 
 
 
196
  setupEventListeners() {
197
  // VT100 frame toggle
198
  const toggleLink = document.getElementById('toggleFrame');
@@ -206,6 +214,53 @@ class KLH10WebInterface {
206
  });
207
  }
208
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
  // Simple mode
210
  document.getElementById('autoBootBtn').addEventListener('click', () => this.autoBoot());
211
  document.getElementById('showAdvanced').addEventListener('click', (e) => {
 
108
  this.terminal.onData((data) => {
109
  if (this.autoBootInProgress) return; // Block input during auto-boot
110
  if (this.worker && this.emulatorReady && this.inputRingBuffer) {
111
+ // Apply Ctrl sticky modifier from key toolbar
112
+ if (this.ctrlActive && data.length === 1 && data >= '@' && data <= '~') {
113
+ data = String.fromCharCode(data.toUpperCase().charCodeAt(0) - 64);
114
+ this.ctrlActive = false;
115
+ const ctrlBtn = document.querySelector('.key-ctrl');
116
+ if (ctrlBtn) ctrlBtn.classList.remove('active');
117
+ }
118
+
119
  // Echo input based on both mode and echo setting
120
  if (this.inRuncmdMode && this.terminalEchoEnabled) {
121
  // Handle special characters
 
129
  this.terminal.write(data);
130
  }
131
  }
132
+
133
+ this.sendInput(data);
 
 
 
 
 
 
 
 
 
 
 
 
134
  }
135
  });
136
 
 
182
  // Cell dimensions are approximately: width ~ fontSize * 0.6, height ~ fontSize * 1.2
183
  const maxByWidth = screenWidth / (80 * 0.6);
184
  const maxByHeight = screenHeight / (24 * 1.2);
185
+ const fontSize = Math.max(4, Math.min(Math.floor(Math.min(maxByWidth, maxByHeight)), 32));
186
 
187
  this.terminal.options.fontSize = fontSize;
188
  this.fitAddon.fit();
189
  this.terminal.resize(80, 24);
190
  }
191
 
192
+ // Send input data to the emulator via ring buffer
193
+ sendInput(data) {
194
+ if (!this.worker || !this.emulatorReady || !this.inputRingBuffer) return;
195
+ for (let i = 0; i < data.length; i++) {
196
+ const char = data[i];
197
+ if (!this.inputRingBuffer.writeInputChar(char)) {
198
+ console.warn('Main: Input ring buffer full, character dropped');
199
+ break;
200
+ }
201
+ }
202
+ }
203
+
204
  setupEventListeners() {
205
  // VT100 frame toggle
206
  const toggleLink = document.getElementById('toggleFrame');
 
214
  });
215
  }
216
 
217
+ // Key toolbar toggle (desktop)
218
+ const keybarToggle = document.getElementById('toggleKeybar');
219
+ if (keybarToggle) {
220
+ keybarToggle.addEventListener('click', (e) => {
221
+ e.preventDefault();
222
+ const toolbar = document.getElementById('keyToolbar');
223
+ const isVisible = toolbar.style.display === 'flex';
224
+ toolbar.style.display = isVisible ? '' : 'flex';
225
+ e.target.textContent = isVisible ? 'Show Key Toolbar' : 'Hide Key Toolbar';
226
+ });
227
+ }
228
+
229
+ // Key toolbar buttons
230
+ this.ctrlActive = false;
231
+ const keyToolbar = document.getElementById('keyToolbar');
232
+ if (keyToolbar) {
233
+ const keyMap = {
234
+ 'esc': '\x1b',
235
+ 'tab': '\t',
236
+ 'up': '\x1b[A',
237
+ 'down': '\x1b[B',
238
+ 'left': '\x1b[D',
239
+ 'right': '\x1b[C',
240
+ 'ctrl-c': '\x03',
241
+ 'ctrl-z': '\x1a',
242
+ 'ctrl-d': '\x04',
243
+ };
244
+
245
+ keyToolbar.addEventListener('click', (e) => {
246
+ const btn = e.target.closest('button');
247
+ if (!btn) return;
248
+ e.preventDefault();
249
+
250
+ const key = btn.dataset.key;
251
+ if (key === 'ctrl') {
252
+ // Toggle Ctrl sticky modifier
253
+ this.ctrlActive = !this.ctrlActive;
254
+ btn.classList.toggle('active', this.ctrlActive);
255
+ } else if (keyMap[key]) {
256
+ this.sendInput(keyMap[key]);
257
+ }
258
+
259
+ // Refocus terminal so soft keyboard stays open
260
+ this.terminal.focus();
261
+ });
262
+ }
263
+
264
  // Simple mode
265
  document.getElementById('autoBootBtn').addEventListener('click', () => this.autoBoot());
266
  document.getElementById('showAdvanced').addEventListener('click', (e) => {