termites 1.0.10 → 1.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/server.js +34 -14
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "termites",
3
- "version": "1.0.10",
3
+ "version": "1.0.12",
4
4
  "description": "Web terminal with server-client architecture for remote shell access",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/server.js CHANGED
@@ -966,7 +966,14 @@ class TermitesServer {
966
966
  if (mod) {
967
967
  modifiers[mod] = !modifiers[mod];
968
968
  btn.classList.toggle('active', modifiers[mod]);
969
- console.log('Modifier toggled:', mod, modifiers[mod]);
969
+ // Set timeout to auto-reset Ctrl after 10 seconds (for IME users)
970
+ if (mod === 'ctrl' && modifiers.ctrl) {
971
+ if (window.ctrlTimeout) clearTimeout(window.ctrlTimeout);
972
+ window.ctrlTimeout = setTimeout(() => {
973
+ modifiers.ctrl = false;
974
+ btn.classList.remove('active');
975
+ }, 10000);
976
+ }
970
977
  // Don't focus terminal when toggling modifier, keep keyboard open
971
978
  return;
972
979
  }
@@ -995,6 +1002,7 @@ class TermitesServer {
995
1002
  // Reset modifiers after use
996
1003
  modifiers.ctrl = false;
997
1004
  modifiers.alt = false;
1005
+ if (window.ctrlTimeout) { clearTimeout(window.ctrlTimeout); window.ctrlTimeout = null; }
998
1006
  toolbar.querySelectorAll('.mod-btn').forEach(b => b.classList.remove('active'));
999
1007
  }
1000
1008
  // Only focus terminal for non-modifier buttons
@@ -1057,20 +1065,23 @@ class TermitesServer {
1057
1065
  term.loadAddon(fitAddon);
1058
1066
  term.open(document.getElementById('terminal-container'));
1059
1067
  fitAddon.fit();
1068
+ let ctrlTimeout = null;
1060
1069
  term.onData(data => {
1061
1070
  if (ws?.readyState === WebSocket.OPEN && selectedClientId) {
1062
1071
  let sendData = data;
1063
- console.log('Input received:', data, 'Ctrl active:', modifiers.ctrl);
1064
1072
  // Apply Ctrl modifier to keyboard input
1065
- if (modifiers.ctrl && data.length === 1) {
1066
- const code = data.toUpperCase().charCodeAt(0);
1073
+ if (modifiers.ctrl) {
1074
+ // Handle single character or IME input
1075
+ const char = data.length >= 1 ? data[0] : '';
1076
+ const code = char.toUpperCase().charCodeAt(0);
1067
1077
  if (code >= 65 && code <= 90) { // A-Z
1068
1078
  sendData = String.fromCharCode(code - 64);
1069
- console.log('Sending Ctrl+' + data.toUpperCase());
1079
+ console.log('Sending Ctrl+' + char.toUpperCase());
1080
+ // Reset Ctrl after successful use
1081
+ modifiers.ctrl = false;
1082
+ if (ctrlTimeout) { clearTimeout(ctrlTimeout); ctrlTimeout = null; }
1083
+ document.querySelectorAll('.mod-btn[data-mod="ctrl"]').forEach(b => b.classList.remove('active'));
1070
1084
  }
1071
- // Reset Ctrl after use
1072
- modifiers.ctrl = false;
1073
- document.querySelectorAll('.mod-btn').forEach(b => b.classList.remove('active'));
1074
1085
  }
1075
1086
  ws.send(JSON.stringify({ type: 'input', clientId: selectedClientId, text: sendData }));
1076
1087
  term.scrollToBottom();
@@ -1085,17 +1096,24 @@ class TermitesServer {
1085
1096
  }));
1086
1097
  }
1087
1098
  }
1099
+ function isMobileDevice() {
1100
+ return 'ontouchstart' in window || navigator.maxTouchPoints > 0 ||
1101
+ /Mobile|Android|iPhone|iPad|iPod|webOS|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
1102
+ }
1088
1103
  function handleViewportResize() {
1089
- // Adjust body height to visual viewport (handles mobile keyboard)
1090
- if (window.visualViewport) {
1104
+ // Only adjust body height on mobile devices (handles keyboard popup)
1105
+ if (isMobileDevice() && window.visualViewport) {
1091
1106
  const vh = window.visualViewport.height;
1092
1107
  document.body.style.height = vh + 'px';
1093
1108
  // Scroll viewport to top to prevent offset issues
1094
1109
  window.scrollTo(0, 0);
1110
+ } else {
1111
+ // On desktop, use full viewport height
1112
+ document.body.style.height = '';
1095
1113
  }
1096
1114
  handleResize();
1097
1115
  }
1098
- window.addEventListener('resize', handleResize);
1116
+ window.addEventListener('resize', handleViewportResize);
1099
1117
  window.addEventListener('orientationchange', () => {
1100
1118
  // Delay fit after orientation change to let browser settle
1101
1119
  setTimeout(handleViewportResize, 100);
@@ -1103,10 +1121,12 @@ class TermitesServer {
1103
1121
  // Also handle visual viewport changes (mobile keyboard show/hide)
1104
1122
  if (window.visualViewport) {
1105
1123
  window.visualViewport.addEventListener('resize', handleViewportResize);
1106
- window.visualViewport.addEventListener('scroll', () => window.scrollTo(0, 0));
1107
- // Initial adjustment
1108
- handleViewportResize();
1124
+ window.visualViewport.addEventListener('scroll', () => {
1125
+ if (isMobileDevice()) window.scrollTo(0, 0);
1126
+ });
1109
1127
  }
1128
+ // Initial adjustment
1129
+ handleViewportResize();
1110
1130
  connect();
1111
1131
  applyTheme(currentTheme);
1112
1132
  }