Files
infinitefusion-e18/Data/Scripts/020_System and utilities/001_PSystem_Controls.rb

292 lines
9.0 KiB
Ruby

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
TAB = 9
A = 11
B = 12
C = 13
X = 14
Y = 15
Z = 16
L = 17
R = 18
ENTER = 19
ESC = 20
SHIFT = 21
CTRL = 22
ALT = 23
BACKSPACE = 24
DELETE = 25
HOME = 26
ENDKEY = 27
F5 = F = 28
ONLYF5 = 29
F6 = 30
F7 = 31
F8 = 32
F9 = 33
LeftMouseKey = 1
RightMouseKey = 2
# GetAsyncKeyState or GetKeyState will work here
@GetKeyState = Win32API.new("user32","GetAsyncKeyState","i","i")
@GetForegroundWindow = Win32API.new("user32","GetForegroundWindow","","i")
# All key states to check
CheckKeyStates = [0x01,0x02,0x08,0x09,0x0D,0x10,0x11,0x12,0x1B,0x20,0x21,0x22,
0x23,0x24,0x25,0x26,0x27,0x28,0x2E,0x30,0x31,0x32,0x33,0x34,
0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,0x50,0x51,0x52,0x53,
0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x6A,0x6B,0x6D,0x6F,0x74,
0x75,0x76,0x77,0x78,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xDB,0xDC,
0xDD,0xDE] # 74 in total
# 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
@keystate[i] = 0 if !@keystate[i]
@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
# $fullInputUpdate is true during keyboard text entry
toCheck = ($fullInputUpdate) ? 0...256 : CheckKeyStates
if @keystate
for i in toCheck
# just noting that the state should be updated
# instead of thunking to Win32 256 times
@stateUpdated[i] = false
# If there is a repeat count, update anyway
# (will normally apply only to a very few keys)
updateKeyState(i) if !@keystate[i] || @keystate[i]>0
end
else
@stateUpdated = []
@keystate = []
@triggerstate = []
@releasestate = []
for i in toCheck
@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 then return [0x28] # Down
when Input::LEFT then return [0x25] # Left
when Input::RIGHT then return [0x27] # Right
when Input::UP then return [0x26] # Up
when Input::TAB then return [0x09] # Tab
when Input::A then return [0x5A, 0x57, 0x59, 0x10] # Z, W, Y, Shift
when Input::B then return [0x58, 0x1B] # X, ESC
when Input::C then return [0x43, 0x0D, 0x20] # C, ENTER, Space
# when Input::X then return [0x41] # A
# when Input::Y then return [0x53] # S
# when Input::Z then return [0x44] # D
when Input::L then return [0x41, 0x51, 0x21] # A, Q, Page Up
when Input::R then return [0x53, 0x22] # S, Page Down
when Input::ENTER then return [0x0D] # ENTER
when Input::ESC then return [0x1B] # ESC
when Input::SHIFT then return [0x10] # Shift
when Input::CTRL then return [0x11] # Ctrl
when Input::ALT then return [0x12] # Alt
when Input::BACKSPACE then return [0x08] # Backspace
when Input::DELETE then return [0x2E] # Delete
when Input::HOME then return [0x24] # Home
when Input::ENDKEY then return [0x23] # End
when Input::F5 then return [0x46, 0x74, 0x09] # F, F5, Tab
when Input::ONLYF5 then return [0x74] # F5
when Input::F6 then return [0x75] # F6
when Input::F7 then return [0x76] # F7
when Input::F8 then return [0x77] # F8
when Input::F9 then return [0x78] # F9
end
return []
end
def self.dir4
button = 0
repeatcount = 0
return 0 if self.press?(Input::DOWN) && self.press?(Input::UP)
return 0 if self.press?(Input::LEFT) && self.press?(Input::RIGHT)
for b in [Input::DOWN,Input::LEFT,Input::RIGHT,Input::UP]
rc = self.count(b)
if rc>0 && (repeatcount==0 || rc<repeatcount)
button = b
repeatcount = rc
end
end
return button
end
def self.dir8
buttons = []
for b in [Input::DOWN,Input::LEFT,Input::RIGHT,Input::UP]
rc = self.count(b)
buttons.push([b,rc]) if rc>0
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
return 0 if (buttons[0][0]==Input::DOWN && buttons[1][0]==Input::UP)
return 0 if (buttons[0][0]==Input::LEFT && buttons[1][0]==Input::RIGHT)
end
buttons.sort! { |a,b| a[1]<=>b[1] }
updown = 0
leftright = 0
for b in buttons
updown = b[0] if updown==0 && (b[0]==Input::UP || b[0]==Input::DOWN)
leftright = b[0] if leftright==0 && (b[0]==Input::LEFT || b[0]==Input::RIGHT)
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.triggerex?(key)
return false if !@triggerstate
updateKeyState(key)
return @triggerstate[key]
end
def self.repeatex?(key)
return false if !@keystate
updateKeyState(key)
return @keystate[key]==1 || (@keystate[key]>Graphics.frame_rate/2 && (@keystate[key]&1)==0)
end
def self.releaseex?(key)
return false if !@releasestate
updateKeyState(key)
return @releasestate[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')
return (@GetCursorPos.call(pos)!=0) ? pos.unpack('ll') : [nil,nil]
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')
return pos.unpack('ll') if screenToClient.call(Win32API.pbFindRgssWindow,pos)!=0
return nil
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)
x, y = screen_to_client(*getMouseGlobalPos)
return nil unless x and y
width, height = Win32API.client_size
if catch_anywhere or (x>=0 and y>=0 and x<width and y<height)
return x, y
end
return nil
end
def del
return if @oldcursor==nil
@SetClassLong.call(Win32API.pbFindRgssWindow,-12,@oldcursor)
@oldcursor = nil
end
end