|  |  |  | @ -1,6 +1,6 @@ | 
			
		
	
		
			
				
					|  |  |  |  | window.initSoftKeyboard = function (screen) { | 
			
		
	
		
			
				
					|  |  |  |  |   const input = qs('#softkb-input') | 
			
		
	
		
			
				
					|  |  |  |  |   if (!input) return // abort, we're not on the terminal page
 | 
			
		
	
		
			
				
					|  |  |  |  | window.initSoftKeyboard = function (screen, input) { | 
			
		
	
		
			
				
					|  |  |  |  |   const keyInput = qs('#softkb-input') | 
			
		
	
		
			
				
					|  |  |  |  |   if (!keyInput) return // abort, we're not on the terminal page
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   let keyboardOpen = false | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -8,97 +8,101 @@ window.initSoftKeyboard = function (screen) { | 
			
		
	
		
			
				
					|  |  |  |  |     if (!keyboardOpen) return | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     let [x, y] = screen.gridToScreen(screen.cursor.x, screen.cursor.y, true) | 
			
		
	
		
			
				
					|  |  |  |  |     input.style.transform = `translate(${x}px, ${y}px)` | 
			
		
	
		
			
				
					|  |  |  |  |     keyInput.style.transform = `translate(${x}px, ${y}px)` | 
			
		
	
		
			
				
					|  |  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   input.addEventListener('focus', () => { | 
			
		
	
		
			
				
					|  |  |  |  |   keyInput.addEventListener('focus', () => { | 
			
		
	
		
			
				
					|  |  |  |  |     keyboardOpen = true | 
			
		
	
		
			
				
					|  |  |  |  |     updateInputPosition() | 
			
		
	
		
			
				
					|  |  |  |  |   }) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   input.addEventListener('blur', () => (keyboardOpen = false)) | 
			
		
	
		
			
				
					|  |  |  |  |   keyInput.addEventListener('blur', () => (keyboardOpen = false)) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   screen.on('cursor-moved', updateInputPosition) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   window.kbOpen = function openSoftKeyboard (open) { | 
			
		
	
		
			
				
					|  |  |  |  |     keyboardOpen = open | 
			
		
	
		
			
				
					|  |  |  |  |     updateInputPosition() | 
			
		
	
		
			
				
					|  |  |  |  |     if (open) input.focus() | 
			
		
	
		
			
				
					|  |  |  |  |     else input.blur() | 
			
		
	
		
			
				
					|  |  |  |  |     if (open) keyInput.focus() | 
			
		
	
		
			
				
					|  |  |  |  |     else keyInput.blur() | 
			
		
	
		
			
				
					|  |  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   // Chrome for Android doesn't send proper keydown/keypress events with
 | 
			
		
	
		
			
				
					|  |  |  |  |   // real key values instead of 229 “Unidentified,” so here's a workaround
 | 
			
		
	
		
			
				
					|  |  |  |  |   // that deals with the input composition events.
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   let lastCompositionString = '' | 
			
		
	
		
			
				
					|  |  |  |  |   let compositing = false | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   // sends the difference between the last and the new composition string
 | 
			
		
	
		
			
				
					|  |  |  |  |   let sendInputDelta = function (newValue) { | 
			
		
	
		
			
				
					|  |  |  |  |     let resend = false | 
			
		
	
		
			
				
					|  |  |  |  |     if (newValue.length > lastCompositionString.length) { | 
			
		
	
		
			
				
					|  |  |  |  |       if (newValue.startsWith(lastCompositionString)) { | 
			
		
	
		
			
				
					|  |  |  |  |         // characters have been added at the end
 | 
			
		
	
		
			
				
					|  |  |  |  |         Input.sendString(newValue.substr(lastCompositionString.length)) | 
			
		
	
		
			
				
					|  |  |  |  |         input.sendString(newValue.substr(lastCompositionString.length)) | 
			
		
	
		
			
				
					|  |  |  |  |       } else resend = true | 
			
		
	
		
			
				
					|  |  |  |  |     } else if (newValue.length < lastCompositionString.length) { | 
			
		
	
		
			
				
					|  |  |  |  |       if (lastCompositionString.startsWith(newValue)) { | 
			
		
	
		
			
				
					|  |  |  |  |         // characters have been removed at the end
 | 
			
		
	
		
			
				
					|  |  |  |  |         Input.sendString('\b'.repeat(lastCompositionString.length - | 
			
		
	
		
			
				
					|  |  |  |  |         input.sendString('\b'.repeat(lastCompositionString.length - | 
			
		
	
		
			
				
					|  |  |  |  |           newValue.length)) | 
			
		
	
		
			
				
					|  |  |  |  |       } else resend = true | 
			
		
	
		
			
				
					|  |  |  |  |     } else if (newValue !== lastCompositionString) resend = true | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     if (resend) { | 
			
		
	
		
			
				
					|  |  |  |  |       // the entire string changed; resend everything
 | 
			
		
	
		
			
				
					|  |  |  |  |       Input.sendString('\b'.repeat(lastCompositionString.length) + | 
			
		
	
		
			
				
					|  |  |  |  |       input.sendString('\b'.repeat(lastCompositionString.length) + | 
			
		
	
		
			
				
					|  |  |  |  |         newValue) | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  |     lastCompositionString = newValue | 
			
		
	
		
			
				
					|  |  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   input.addEventListener('keydown', e => { | 
			
		
	
		
			
				
					|  |  |  |  |   keyInput.addEventListener('keydown', e => { | 
			
		
	
		
			
				
					|  |  |  |  |     if (e.key === 'Unidentified') return | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     input.value = '' | 
			
		
	
		
			
				
					|  |  |  |  |     keyInput.value = '' | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     if (e.key === 'Backspace') { | 
			
		
	
		
			
				
					|  |  |  |  |       e.preventDefault() | 
			
		
	
		
			
				
					|  |  |  |  |       Input.sendString('\b') | 
			
		
	
		
			
				
					|  |  |  |  |       input.sendString('\b') | 
			
		
	
		
			
				
					|  |  |  |  |     } else if (e.key === 'Enter') { | 
			
		
	
		
			
				
					|  |  |  |  |       e.preventDefault() | 
			
		
	
		
			
				
					|  |  |  |  |       Input.sendString('\x0d') | 
			
		
	
		
			
				
					|  |  |  |  |       input.sendString('\x0d') | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  |   }) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   input.addEventListener('keypress', e => { | 
			
		
	
		
			
				
					|  |  |  |  |   keyInput.addEventListener('keypress', e => { | 
			
		
	
		
			
				
					|  |  |  |  |     // prevent key duplication on iOS (because Safari *does* send proper events)
 | 
			
		
	
		
			
				
					|  |  |  |  |     e.stopPropagation() | 
			
		
	
		
			
				
					|  |  |  |  |   }) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   input.addEventListener('input', e => { | 
			
		
	
		
			
				
					|  |  |  |  |   keyInput.addEventListener('input', e => { | 
			
		
	
		
			
				
					|  |  |  |  |     e.stopPropagation() | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     if (e.isComposing) { | 
			
		
	
		
			
				
					|  |  |  |  |       sendInputDelta(e.data) | 
			
		
	
		
			
				
					|  |  |  |  |     } else { | 
			
		
	
		
			
				
					|  |  |  |  |       if (e.inputType === 'insertCompositionText') Input.sendString(e.data) | 
			
		
	
		
			
				
					|  |  |  |  |       if (e.inputType === 'insertCompositionText') input.sendString(e.data) | 
			
		
	
		
			
				
					|  |  |  |  |       else if (e.inputType === 'deleteContentBackward') { | 
			
		
	
		
			
				
					|  |  |  |  |         lastCompositionString = '' | 
			
		
	
		
			
				
					|  |  |  |  |         sendInputDelta('') | 
			
		
	
		
			
				
					|  |  |  |  |       } else if (e.inputType === 'insertText') { | 
			
		
	
		
			
				
					|  |  |  |  |         Input.sendString(e.data) | 
			
		
	
		
			
				
					|  |  |  |  |         input.sendString(e.data) | 
			
		
	
		
			
				
					|  |  |  |  |       } | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  |   }) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   input.addEventListener('compositionstart', e => { | 
			
		
	
		
			
				
					|  |  |  |  |   keyInput.addEventListener('compositionstart', e => { | 
			
		
	
		
			
				
					|  |  |  |  |     lastCompositionString = '' | 
			
		
	
		
			
				
					|  |  |  |  |     compositing = true | 
			
		
	
		
			
				
					|  |  |  |  |     console.log('compositionstart') | 
			
		
	
		
			
				
					|  |  |  |  |   }) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   input.addEventListener('compositionend', e => { | 
			
		
	
		
			
				
					|  |  |  |  |   keyInput.addEventListener('compositionend', e => { | 
			
		
	
		
			
				
					|  |  |  |  |     lastCompositionString = '' | 
			
		
	
		
			
				
					|  |  |  |  |     compositing = false | 
			
		
	
		
			
				
					|  |  |  |  |     input.value = '' | 
			
		
	
		
			
				
					|  |  |  |  |     console.log('compositionend') | 
			
		
	
		
			
				
					|  |  |  |  |     keyInput.value = '' | 
			
		
	
		
			
				
					|  |  |  |  |   }) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   screen.on('open-soft-keyboard', () => input.focus()) | 
			
		
	
		
			
				
					|  |  |  |  |   screen.on('open-soft-keyboard', () => keyInput.focus()) | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
	
		
			
				
					|  |  |  | 
 |