const inputFields = document.getElementsByTagName('input')
const replacements = {
  a: "b"
}
// Create a simple keyboard
const buttonA = document.createElement('button')
buttonA.textContent = 'Insert "a"'
const buttonB = document.createElement('button')
buttonB.textContent = 'Insert "b"'
const keyboard = document.createElement('div')
keyboard.appendChild(buttonA)
keyboard.appendChild(buttonB)

let selectedInput = null

addChar = (i, char) => {
    const start = i.selectionStart
    i.value = i.value.slice(0, start) + char + i.value.slice(i.selectionEnd)
    // Updating the input value moves the caret to the end by default
    i.selectionStart = i.selectionEnd = start + 1
}

for (const input of inputFields) {
  input.onkeydown = e => {
    const character = replacements[e.key]
    if (!character) return
    addChar(input, character)
    return false
  }
  // Handle the case where the input is already focused
  if (document.activeElement === input) {
    input.parentElement.appendChild(keyboard)
    selectedInput = input
  }
  input.onfocus = e => {
    input.parentElement.appendChild(keyboard)
    selectedInput = input
  }
  // https://css-tricks.com/a-css-approach-to-trap-focus-inside-of-an-element/
  input.ontransitionend = e => {
    if (input.matches(':focus') || keyboard.contains(document.activeElement)) e.target.focus()
    else {
      input.parentElement.removeChild(keyboard)
      selectedInput = null
    }
  }
}

keyboard.onclick = e => {
  return false
}
buttonA.onmouseup = e => {
  if (selectedInput) addChar(selectedInput, "a")
}
buttonB.onmouseup = e => {
  if (selectedInput) addChar(selectedInput, "b")
}