include, plotscr.hsd
include, scancode.hsi

global variable (1, tick)
global variable (2, input hash)
global variable (3, show hash)
global variable (4, current mode)  # mode:... constant
define constant (0, mode:keyboard)
define constant (1, mode:joystick)

define constant (4, str:input text)

#Removed from plotscr.hsd
script, set extended scancodes enabled, hsd:bit=1, begin
  if(hsd:bit) then (hsd:bit := 256)
  write general(177, (read general(177),and,-257) + hsd:bit)
end

plotscript, main, begin
  suspend player

  while (true) do (
    if (current mode == mode:keyboard) then (keyboard main)
    if (current mode == mode:joystick) then (joystick main)
  )
end

script, check mode change, begin
  variable (mode, sl)
  mode := current mode
  if (key is pressed (key:ctrl)) then (
    if (keypress (key:1)) then (mode := mode:keyboard)
    if (keypress (key:2)) then (mode := mode:joystick)
  )

  subscript, mouse on slice, lookup, begin
    return (slice collide point (lookup slice (lookup), mouse pixel x, mouse pixel y))
  end

  if (mouse release) then (
    if (mouse on slice (sli:keyboard tab)) then (mode := mode:keyboard)
    if (mouse on slice (sli:joystick tab)) then (mode := mode:joystick)
  )

  return (mode <> current mode)
  current mode := mode
end

plotscript, keyboard main, begin
  variable (collection)
  collection := load slice collection (0)
  set slice lookups (sprite layer)

  while (check mode change == false) do, begin
    tick += 1
    if (key is pressed(key:ctrl) && keypress(key:t)) then (
      enable input text (not (input text enabled))
      $str:input text=""
    )
    if (key is pressed(key:ctrl) && keypress(key:e)) then (
      set extended scancodes enabled (extended scancodes enabled, xor, true)
    )
    if (key is pressed(key:ctrl) && keypress(key:h)) then (
      show hash := show hash, xor, true
    )
    if (key is pressed(key:ctrl) && keypress(key:k)) then (
      write preference bit (47, (true, xor, read preference bit (47)))  # "!Map joystick controls to keyboard keys for scripts"
    )

    update keyboard strings
    update buttons (cancelkey, 127)
    wait
  end
  free slice (collection)
end

script, create joystick button grid, begin
  variable(template, i, sl)
  template := lookup slice (sli:joy button template)
  for (i, 0, 31) do (
    sl := clone slice(template)
    $0=""
    append number(0, i + 1)
    set slice text(first text child(sl), 0)
    set slice lookup(sl, 100 + joy:button 1 + i)
  )
  free slice(template)
end

plotscript, joystick main, begin
  variable (collection, template, player)
  collection := load slice collection (2)
  create joystick button grid
  set slice lookups (sprite layer)  # Only needed for the Control keys, I set the lookups of buttons directly instead of extra0

  while (check mode change == false) do, begin
    tick += 1
    if (keypress(key:plus) && player < 15) then (player += 1)
    if (keypress(key:minus) && player > 0) then (player -= 1)

    if (key is pressed(key:ctrl) && keypress(key:d)) then (
      write preference bit (53, (true, xor, read preference bit (53)))  # "!Map joystick (left) stick to dpad"
    )

    update joystick strings (player)
    update buttons (cancelkey, anykey, player)  #-9 to -1
    update buttons (joy:button1, joy:button32, player, true)
    # Duplicate buttons
    update buttons (joy:button1, joy:button32, player, true, lookup slice(sli:right stick))
    update buttons (joy:button1, joy:button32, player, false, lookup slice(sli:button grid))

    # Move sticks
    update stick (axis:X, axis:Y, player, lookup slice(100 + joy:left stick))
    update stick (axis:RightX, axis:RightY, player, lookup slice(100 + joy:right stick))

    wait
  end

  free slice(collection)
end

script, update keyboard strings, begin
  if (extended scancodes enabled) then (
    $0="OFF"
  ) else (
    $0="ON"
  )
  update str (sli:scancode backcompat string, 0)

  if (show hash) then (
    $2="Hash:"
    append number (2, abs(input hash))
  ) else (
    $2=""
  )
  update str (sli:hash string, 2)


  $3="Ctrl+T: enable text input"
  if (input text enabled) then (
    get input text (5)

    variable (i)
    for (i, 1, string length (5)) do (
      input hash += (input hash * 333667), xor, ascii from string (5, i)
    )

    str:input text $+ 5
    if (string length (str:input text) > 33) then (
      trim string (str:input text, string length (str:input text) -- 33 + 1, 33)
    )
    if (keypress (key:backspace)) then (
      trim string (str:input text, string length (str:input text), 1)
    )
    $3="Input :"
    3 $+ str:input text
  )
  update str (sli:input string, 3)

  if (read preference bit (47)) then (  # "!Map joystick controls to keyboard keys for scripts"
    $3="Ctrl+K: joysticks not mapped to keyboard"
  ) else (
    $3="Ctrl+K: joysticks mapped to keyboard"
  )
  update str (sli: map joy to keys, 3)
end

script, update str, lookup, strid, begin
  variable(sl)
  sl := lookup slice(lookup)
  set slice text(sl, strid)
end


#Keyboard scancodes are stored in extra0, which we copy
#into the lookup for convenience (and for testing)
script, set slice lookups, sl, begin
  if (get slice lookup (sl) == 0 && get slice extra (sl, 0)) then (
    # Offet by 100 to allow negative scancode while avoiding disallowed negative lookup codes
    set slice lookup (sl, 100 + get slice extra (sl, 0))
  )

  variable (child)
  child := first child (sl)
  while (child) do, begin
    set slice lookups (child)
    child := next sibling (child)
  end
end

#Update appearance of the button slices
#is game button: buttons on the gamepad itself (unlike Use, etc) are styled a bit differently
script, update buttons, first, last, player = 0, gamepad button = false, root = 0, begin
  variable (key, sl, st, box style)
  for (key, first, last) do, begin
    sl := lookup slice (100 + key, root)
    if (sl == 0) then (continue)

    # keyboard buttons use box styles 1-4
    box style := 1 + keyval(key, player)
    if (gamepad button && box style == 1) then (
      # joy buttons use box styles 0 and 2-4
      box style := 0
    )

    if (slice is rect(sl)) then (
      set rect style(sl, box style)
      if (gamepad button) then (set rect border(sl, border:none))
    ) else if (slice is ellipse(sl)) then (
      set ellipse fill col(sl, get box style color(box style))
    )

    if (keyval(key, player)) then (
      input hash += (input hash * 333667), xor, (tick * 367 + key * 336667 + keyval(key, player) * 3336677)  # primes
    )
  end
end

script, update joystick strings, player, begin
  subscript, update axis, axis, lookup, strid, begin
    variable(sl)
    append number (strid, joystick axis(axis, 100, player))
    sl := lookup slice (lookup)
    set slice text (sl, strid)
  end

  update axis(axis:X, sli:left X axis, $0="X")
  update axis(axis:Y, sli:left Y axis, $0="Y")
  update axis(axis:RightX, sli:right X axis, $0="X")
  update axis(axis:RightY, sli:right Y axis, $0="Y")
  update axis(axis:L2, sli:L2 axis, $0="")
  update axis(axis:R2, sli:R2 axis, $0="")

  get joystick name (0, player)
  update str (sli:joystick name, 0)
  string sprintf (0, $0="%d", player)
  if (player == 0) then ($0+" (any)")
  update str (sli:joystick num, 0)
  string sprintf (0, $0="%d buttons %d axes %d hats", joystick button count(player), joystick axis count(player), joystick hat count(player))
  update str (sli:joystick info, 0)

  if (read preference bit (53)) then (  # "!Map joystick (left) stick to dpad buttons"
    $0="NO"
  ) else (
    $0="YES"
  )
  update str (sli:joystick dpad map, 0)
end

script, update stick, axis x, axis y, player, sl, begin
  set slice x (sl, joystick axis (axis x, 3, player))
  set slice y (sl, joystick axis (axis y, 3, player))
end
