def pbSameThread(wnd)
  return false if wnd==0
  processid=[0].pack('l')
  getCurrentThreadId=Win32API.new('kernel32','GetCurrentThreadId', '%w()','l')
  getWindowThreadProcessId=Win32API.new('user32','GetWindowThreadProcessId', '%w(l p)','l')
  threadid=getCurrentThreadId.call
  wndthreadid=getWindowThreadProcessId.call(wnd,processid)
  return (wndthreadid==threadid)
end



module Input
  DOWN  = 2
  LEFT  = 4
  RIGHT = 6
  UP    = 8
  A     = 11
  B     = 12
  C     = 13
  X     = 14
  Y     = 15
  Z     = 16
  L     = 17
  R     = 18
  SHIFT = 21
  CTRL  = 22
  ALT   = 23
  F5    = 25
  F6    = 26
  F7    = 27
  F8    = 28
  F9    = 29
  LeftMouseKey   = 1
  RightMouseKey  = 2
  CenterMouseKey = 0
  # GetAsyncKeyState or GetKeyState will work here
  @GetKeyState=Win32API.new("user32", "GetAsyncKeyState", "i", "i")
  @GetForegroundWindow=Win32API.new("user32", "GetForegroundWindow", "", "i")
  # Returns whether a key is being pressed

  def self.getstate(key)
    return (@GetKeyState.call(key)&0x8000)>0
  end

  def self.updateKeyState(i)
    gfw=pbSameThread(@GetForegroundWindow.call())
    if !@stateUpdated[i]
      newstate=self.getstate(i) && gfw
      @triggerstate[i]=(newstate&&@keystate[i]==0)
      @releasestate[i]=(!newstate&&@keystate[i]>0)
      @keystate[i]=newstate ? @keystate[i]+1 : 0
      @stateUpdated[i]=true
    end
  end

  def self.update
    if @keystate
      for i in 0...256
        # just noting that the state should be updated
        # instead of thunking to Win32 256 times
        @stateUpdated[i]=false
        if @keystate[i] > 0
          # If there is a repeat count, update anyway
          # (will normally apply only to a very few keys)
          updateKeyState(i)
        end
      end    
    else
      @stateUpdated=[]
      @keystate=[]
      @triggerstate=[]
      @releasestate=[]
      for i in 0...256
        @stateUpdated[i]=true
        @keystate[i]=self.getstate(i) ? 1 : 0
        @triggerstate[i]=false
        @releasestate[i]=false
      end
    end
  end

  def self.buttonToKey(button)
    case button
    when Input::DOWN
      return [0x28] # Down
    when Input::LEFT
      return [0x25] # Left
    when Input::RIGHT
      return [0x27] # Right
    when Input::UP
      return [0x26] # Up
    when Input::A
      return [0x5A,0x10] # Z, Shift
    when Input::B
      return [0x58,0x1B] # X, ESC 
    when Input::C
      return [0x43,0x0D,0x20] # C, ENTER, Space
    when Input::X
      return [0x41] # A
    when Input::Y
      return [0x53] # S
    when Input::Z
      return [0x44] # D
    when Input::L
      return [0x51,0x21] # Q, Page Up
    when Input::R
      return [0x57,0x22] # W, Page Down
    when Input::SHIFT
      return [0x10] # Shift
    when Input::CTRL
      return [0x11] # Ctrl
    when Input::ALT
      return [0x12] # Alt
    when Input::F5
      return [0x74] # F5
    when Input::F6
      return [0x75] # F6
    when Input::F7
      return [0x76] # F7
    when Input::F8
      return [0x77] # F8
    when Input::F9
      return [0x78] # F9
    else
      return []
    end
  end

  def self.dir4
    button=0
    repeatcount=0
    if self.press?(Input::DOWN) && self.press?(Input::UP)
      return 0
    end
    if self.press?(Input::LEFT) && self.press?(Input::RIGHT)
      return 0
    end
    for b in [Input::DOWN,Input::LEFT,Input::RIGHT,Input::UP]
      rc=self.count(b)
      if rc>0
        if repeatcount==0 || rc<repeatcount
          button=b
          repeatcount=rc
        end
      end
    end
    return button
  end

  def self.dir8
    buttons=[]
    for b in [Input::DOWN,Input::LEFT,Input::RIGHT,Input::UP]
      rc=self.count(b)
      if rc>0
        buttons.push([b,rc])
      end
    end
    if buttons.length==0
      return 0
    elsif buttons.length==1
      return buttons[0][0]
    elsif buttons.length==2
      # since buttons sorted by button, no need to sort here
      if (buttons[0][0]==Input::DOWN && buttons[1][0]==Input::UP)
        return 0
      end
      if (buttons[0][0]==Input::LEFT && buttons[1][0]==Input::RIGHT)
        return 0
      end
    end
    buttons.sort!{|a,b| a[1]<=>b[1]}
    updown=0
    leftright=0
    for b in buttons
      if updown==0 && (b[0]==Input::UP || b[0]==Input::DOWN)
        updown=b[0]
      end
      if leftright==0 && (b[0]==Input::LEFT || b[0]==Input::RIGHT)
        leftright=b[0]
      end
    end
    if updown==Input::DOWN
      return 1 if leftright==Input::LEFT
      return 3 if leftright==Input::RIGHT
      return 2
    elsif updown==Input::UP
      return 7 if leftright==Input::LEFT
      return 9 if leftright==Input::RIGHT
      return 8
    else
      return 4 if leftright==Input::LEFT
      return 6 if leftright==Input::RIGHT
      return 0
    end
  end

  def self.count(button)
    for btn in self.buttonToKey(button)
      c=self.repeatcount(btn)
      return c if c>0
    end
    return 0
  end

  def self.release?(button)
    rc=0
    for btn in self.buttonToKey(button)
      c=self.repeatcount(btn)
      return false if c>0
      rc+=1 if self.releaseex?(btn)
    end
    return rc>0
  end

  def self.trigger?(button)
    return self.buttonToKey(button).any? {|item| self.triggerex?(item) }
  end

  def self.repeat?(button)
    return self.buttonToKey(button).any? {|item| self.repeatex?(item) }
  end

  def self.press?(button)
    return self.count(button)>0
  end

  def self.repeatex?(key)
    return false if !@keystate
    updateKeyState(key)
    return @keystate[key]==1 || (@keystate[key]>20 && (@keystate[key]&1)==0)
  end

  def self.releaseex?(key)
    return false if !@releasestate
    updateKeyState(key)
    return @releasestate[key]
  end

  def self.triggerex?(key)
    return false if !@triggerstate
    updateKeyState(key)
    return @triggerstate[key]
  end

  def self.repeatcount(key)
    return 0 if !@keystate
    updateKeyState(key)
    return @keystate[key]
  end

  def self.pressex?(key)
    return self.repeatcount(key)>0
  end
end



# Requires Win32API
module Mouse
  gsm = Win32API.new('user32', 'GetSystemMetrics', 'i', 'i')
  @GetCursorPos = Win32API.new('user32', 'GetCursorPos', 'p', 'i')
  @SetCapture = Win32API.new('user32', 'SetCapture', 'p', 'i')
  @ReleaseCapture = Win32API.new('user32', 'ReleaseCapture', '', 'i')
  module_function
  def getMouseGlobalPos
    pos = [0, 0].pack('ll')
    if @GetCursorPos.call(pos) != 0
      return pos.unpack('ll')
    else
      return nil
    end
  end

  def screen_to_client(x, y)
    return nil unless x and y
    screenToClient = Win32API.new('user32', 'ScreenToClient', %w(l p), 'i')
    pos = [x, y].pack('ll')
    if screenToClient.call(Win32API.pbFindRgssWindow, pos) != 0
      return pos.unpack('ll')
    else
      return nil
    end
  end

  def setCapture
    @SetCapture.call(Win32API.pbFindRgssWindow)
  end

  def releaseCapture
    @ReleaseCapture.call
  end

  # Returns the position of the mouse relative to the game window.
  def getMousePos(catch_anywhere = false)
    resizeFactor=($ResizeFactor) ? $ResizeFactor : 1
    x, y = screen_to_client(*getMouseGlobalPos)
    width, height = Win32API.client_size
    if catch_anywhere or (x >= 0 and y >= 0 and x < width and y < height)
      return (x/resizeFactor).to_i, (y/resizeFactor).to_i
    else
      return nil
    end
  end

  def del
    if @oldcursor == nil
      return
    else
      @SetClassLong.call(Win32API.pbFindRgssWindow,-12, @oldcursor)
      @oldcursor = nil
    end
  end
end
