$apicache = {}
class String
def apicall(*args)
$apicache[self] = Win32API.new(*self.split("|")) unless $apicache.include? self
$apicache[self].call(*args)
end
end
class Symbol
def method_missing(*args, &block)
self.to_s.send(*args, &block)
end
end
class Win32API
WM_ACTIVATEAPP=0x1C
WM_MOUSEMOVE=0x200
WM_MOUSEWHEEL = 0x020A
WM_LBUTTONDOWN = 0x201
WM_RBUTTONDOWN = 0x204
WM_MOUSEDOWN = 0x210
WM_LBUTTONUP = 0x202
WM_RBUTTONUP = 0x205
WM_LBUTTONDBLCLK = 0x203
WM_RBUTTONDBLCLK = 0x204
end
module Roost
module MainWindow
def self.getwndproc
@wndproc
end
def self.setwndproc(obj)
@wndproc=obj
end
def self.addwndproc(obj)
@@wndprocs.push(obj)
end
@@wndprocs=[]
@wndproc = lambda {|hwnd, msg, wp, lp|
@@handle=false
for i in @@wndprocs
i.call(hwnd, msg, wp, lp)
end
return Roost::MainWindow.use_rm_proc(hwnd, msg, wp, lp)
}
def self.use_rm_proc(hwnd,msg,wp,lp)
if (not @@handle)
@@handle=true
return :"user32|CallWindowProc|iiiii|i".apicall(@@oHandle,hwnd,msg,wp,lp)
end
end
def self.disable_rm_proc
@@handle=true
end
def self.enable
Roost::MainWindow.instance_eval do
def self.enable
end
end
Roost::MainWindow.instance_eval do
@msg = "\0"*24
@hwnd = 0
while @hwnd==0
:"user32|GetMessage|piii|v".apicall(@msg, 0, 0, 0)
@kmsg = @msg
:"user32|TranslateMessage|p|v".apicall(@kmsg)
:"user32|DispatchMessage|p|v".apicall(@kmsg)
@hwnd = @msg.unpack("i*")[0]
end
@hdc = :"user32|GetDC|i|i".apicall(@hwnd)
def self.hwnd
return @hwnd
end
def self.hdc
return @hdc
end
def self.findProc(l, n)
lib = :"kernel32|LoadLibrary|p|i".apicall(l);
ret = :"kernel32|GetProcAddress|ip|l".apicall(lib, n);
:"kernel32|FreeLibrary|l|v".apicall(lib)
return ret
end
def self.loadfindProc(l, n)
lib = :"kernel32|LoadLibrary|p|i".apicall(l);
ret = :"kernel32|GetProcAddress|ip|l".apicall(lib, n);
return ret
end
def self.enableWndProc
Roost::MainWindow.instance_eval do
def self.enableWndProc
end
end
@malloc = :"msvcrt|malloc|i|i"
@memcpy = :"msvcrt|memcpy|ipi|v"
sprintf = self.findProc("msvcrt", "sprintf")
rgsseval = self.findProc("RGSS300", "RGSSGetInt")
old = :"user32|GetWindowLong|ll|l".apicall(@hwnd, -4)
buf = @malloc.apicall(1024)
fmt = @malloc.apicall(2048)
sprintfvar = @malloc.apicall(8)
rgssevalvar= @malloc.apicall(8)
oldvar = @malloc.apicall(8)
fmtvar = @malloc.apicall(8)
bufvar = @malloc.apicall(8)
defvar = @malloc.apicall(8)
:"msvcrt|strcpy|pp|p".apicall(fmt, "Roost::MainWindow.getwndproc.call(%d,%d,%d,%d)")
@memcpy.apicall(sprintfvar, [sprintf].pack("i"), 4)
@memcpy.apicall(rgssevalvar,[rgsseval].pack("i"), 4)
@memcpy.apicall(oldvar, [old].pack("i"), 4)
@memcpy.apicall(fmtvar, [fmt].pack("i"), 4)
@memcpy.apicall(bufvar, [buf].pack("i"), 4)
@memcpy.apicall(defvar, [self.findProc("user32", "DefWindowProcA")].pack("i"), 4)
@code = [0x55,0x89,0xe5,0xff,0x75,0x14,
0xff,0x75,0x10,0xff,0x75,0x0c,
0xff,0x75,0x08,0xff,0x35].pack('C*')
@code << [fmtvar].pack('l') << [0xff, 0x35].pack('C*')
@code << [bufvar].pack('l') << [0xff, 0x15].pack('C*')
@code << [sprintfvar].pack("l")
@code << [0xff, 0x15].pack('C*')
@code << [rgssevalvar].pack("l")
=begin
@code << [0x83,0xc4,0x18, 0xff, 0x75, 0x14,
0xff,0x75, 0x10, 0xff, 0x75, 0x0c,
0xff,0x75, 0x08, 0xff, 0x15].pack('C*')
@code << [oldvar].pack("l")
=end
@code << [0x83,0xc4,0x18].pack('C*')
@code << [0xc9,0xc2,0x10,0x00].pack('C*')
#0xD1, 0xE8
@shellcode = @malloc.apicall(2048)
@memcpy.apicall(@shellcode, @code, @code.size)
@@oHandle= :"user32|SetWindowLong|iii|i".apicall(@hwnd, -4, @shellcode)
#Returning Test : should be 5
#Roost::MainWindow.setwndproc (lambda{|hwnd, msg, wp, lp| 5})
#p :"user32|CallWindowProc|iiiii|i".apicall(@shellcode, 0, 0, 0, 0)
end
end
end
end
end
Roost::MainWindow.enable
Roost::MainWindow.enableWndProc
module Mouse
module_function
LKEY,RKEY,MKEY = 1,2,4
DBLCTIME = (Win32API.new('user32','GetDoubleClickTime','','l').call * 60.0 / 1000).round
@count = 0 ## 双击时间计数
@dblc = [] ## 双击记录[key,wait,[mouse_x,mouse_y]]
@move_pos = [] ## 移动记录
@clicks = [] ## 单击记录
def _init_
@press,@toggled=0,0
@pos=[0,0]
Roost::MainWindow.addwndproc (lambda {|hwnd, msg, wp, lp|
Mouse.onLMouseDown if msg==Win32API::WM_LBUTTONDOWN
Mouse.onRMouseDown if msg==Win32API::WM_RBUTTONDOWN
Mouse.onLMouseUp if msg==Win32API::WM_LBUTTONUP
Mouse.onRMouseUp if msg==Win32API::WM_RBUTTONUP
Mouse.onLMouseDD if msg==Win32API::WM_LBUTTONDBLCLK
Mouse.onRMouseDD if msg==Win32API::WM_RBUTTONDBLCLK
if msg==Win32API::WM_MOUSEMOVE
Mouse.setMouse([lp&0xffff,lp>>16])
end
})
@ldown=false
@ltd=false
@rdown=false
@rtd=false
@lup=false
@rup=false
end
def onLMouseDown
@ltd=true
@ltd=false if @ldown
@ldown=true
end
def onLMouseUp
@ldown=false
@ltd=false
end
def onLMouseDD
end
def onRMouseDown
@rtd=true
@rtd=false if @rdown
@rdown=true
end
def onRMouseUp
@rdown=false
@rtd=false
end
def onRMouseDD
end
def setMouse(p)
@pos=p
end
#--------------------------------------------------------------------------
# ## 触发?
#--------------------------------------------------------------------------
def self.toggled?(key)
return @toggled & key != 0
end
#--------------------------------------------------------------------------
# ## 按下?
#--------------------------------------------------------------------------
def Mouse.press?(key)
return @press & key != 0
end
#--------------------------------------------------------------------------
# ## 单击?
#--------------------------------------------------------------------------
def self.click?(key)
return false if key == LKEY and !$click_abled
return @clicks[0] & key == 0 && @clicks[1] & key != 0
end
#--------------------------------------------------------------------------
# ## 双击?
#--------------------------------------------------------------------------
def self.dbl_click?(key)
return false if @dblc.size < 2
## 键值有效
if @dblc[1][0] & key != 0 and @dblc[0][0] & key != 0
## 间隔有效
if @dblc[1][1] - @dblc[0][1] < DBLCTIME
## 坐标有效
if @dblc[1][2] == @dblc[0][2]
return @clicks[0] & key == 0 && @clicks[1] & key != 0
end
end
end
return false
end
def pos
return @pos
end
def update
@press,@toggled=0,0
@press += LKEY if @ldown
@press += RKEY if @rdown
@toggled += LKEY if @ltd
@toggled += RKEY if @rtd
@clicks.shift if @clicks.size >=2
@clicks.push @press
if @dblc.size >= 2
@dblc.clear
@count = 0
end
if @dblc.size == 1 and @count - @dblc[0][1] > DBLCTIME
@dblc.clear
@count = 0
end
if @clicks[0] == 0 and @clicks[1] != 0
if @dblc.size == 1 and @dblc[0][0] != @clicks[1]
@dblc.clear
@count = 0
end
@dblc.push [@press,@count,@pos]
end
@count += 1 unless @dblc.empty?
@move_pos.shift if @move_pos.size >= 2
@move_pos.push @pos
$click_abled=true
end
def down(p)
if (p==LEFT)
return @ldown
else
return @rdown
end
end
end
Mouse._init_
class << Mouse
Win32API.new('user32', 'ShowCursor', 'l', 'l').call(0)
$mousec = Sprite.new
$mousec.z = 10001
$mousec.x = $mousec.y = 1000
$mouse_icon = 'Pointer'
$mousec.bitmap = Cache.system($mouse_icon)
alias wor_mouse_upd_mouse update unless $@
def Mouse.update
wor_mouse_upd_mouse
if $mouse_old_icon.nil? or $mouse_old_icon != $mouse_icon
$mouse_old_icon = $mouse_icon
$mousec.bitmap = Cache.system($mouse_old_icon)
end
if @pos.nil?
$mousec.x = 1000 if $mousec.x != 1000
$mousec.y = 1000 if $mousec.y != 1000
Win32API.new('user32', 'ShowCursor', 'l', 'l').call(1)
else
$mousec.x = @pos[0] if $mousec.x != @pos[0]
$mousec.y = @pos[1] if $mousec.y != @pos[1]
Win32API.new('user32', 'ShowCursor', 'l', 'l').call(0)
end
## 鼠标刷新
$mousec.update
end
#--------------------------------------------------------------------------
# ## 经过?
# obj : 对象实例
# **支持Sprite,Window,Viewport,Rect,Plane,可补充
#--------------------------------------------------------------------------
def Mouse.over?(obj)
case obj
when Sprite
x = obj.x-obj.ox; y = obj.y-obj.oy
unless obj.viewport.nil?
x += obj.viewport.rect.x
y += obj.viewport.rect.y
end
return Mouse.area?(x, y, obj.width, obj.height)
when Window
x = obj.x;y = obj.y
unless obj.viewport.nil?
x += obj.viewport.rect.x
y += obj.viewport.rect.y
end
return Mouse.area?(x, y, obj.width, obj.height)
when Viewport
return Mouse.area?(obj.rect.x, obj.rect.y, obj.rect.width, obj.rect.height)
when Rect
return Mouse.area?(obj.x, obj.y, obj.width, obj.height)
when Plane
x = obj.x;y = obj.y
unless obj.viewport.nil?
x += obj.viewport.rect.x
y += obj.viewport.rect.y
end
return Mouse.area?(x, y, obj.width, obj.height)
end
end
#--------------------------------------------------------------------------
# * Mouse in_area
#--------------------------------------------------------------------------
def Mouse.area?(x, y, width=32, height=32)
return false if @pos == nil
return true if @pos[0] >= x and @pos[0] <= (x+width) and @pos[1] >= y and @pos[1] <= (y+height)
return false
end
end
#==============================================================================
# ## Window_Selectable
#==============================================================================
class Window_Selectable < Window_Base
alias wor_winsel_ini_mouse initialize
alias wor_winsel_upd_mouse update
def initialize(*args)
wor_winsel_ini_mouse(*args)
@scroll_wait = 0
@cursor_wait = 0
end
def update
wor_winsel_upd_mouse
if self.active and self.visible
update_mouse
end
end
def update_mouse
@cursor_wait -= 1 if @cursor_wait > 0
(0...item_max).each do |i|
irect = mouse_rect(i)
irx = self.x + 16 + irect.x - self.ox
iry = self.y + 16 + irect.y - self.oy
result = Mouse.area?(irx, iry, irect.width, irect.height)
move_cursor(i) if result
## 控制单击条件
$click_abled = false if i == @index and !result
end
end
## 鼠标区域
def mouse_rect(i)
rect = item_rect(i)
return rect if rect.width <= 32
rect.x += 4
rect.y += 4
rect.width -= 8
rect.height -= 8
return rect
end
def column_max
return row_max
end
def move_cursor(index)
## 不响应
return if @cursor_wait > 0
return if self.index == index
@scroll_wait -= 1 if @scroll_wait > 0
row1 = self.index / column_max
row2 = index / column_max
bottom = self.top_row + (self.page_row_max - 1)
if row1 == self.top_row and row2 < self.top_row
return if @scroll_wait > 0
self.index = [self.index - column_max, 0].max
@scroll_wait = 4
elsif row1 == bottom and row2 > bottom
return if @scroll_wait > 0
self.index = [self.index + column_max, item_max - 1].min
@scroll_wait = 4
else
self.index = index
end
return if @cursor_wait > 0
Sound.play_cursor
@cursor_wait += 2
end
end
#==============================================================================
# ** Input
#==============================================================================
class << Input
alias wor_input_upd_mouse update unless $@
alias wor_input_trig_mouse trigger? unless $@
alias wor_input_rep_mouse repeat? unless $@
def Input.update
wor_input_upd_mouse
Mouse.update
end
def Input.trigger?(input)
return wor_input_trig_mouse(input) if Mouse.pos.nil?
case input
when Input::B
return (wor_input_trig_mouse(input) or Mouse.click?(Mouse::RKEY))
when Input::C
if SceneManager.scene.is_a?(Scene_Map) and !$game_message.visible
return wor_input_trig_mouse(input)
else
return (wor_input_trig_mouse(input) or Mouse.click?(Mouse::LKEY))
end
else
return wor_input_trig_mouse(input)
end
end
def Input.repeat?(input)
if input == Input::B
return (wor_input_rep_mouse(input) or Mouse.click?(Mouse::RKEY))
else
return wor_input_rep_mouse(input)
end
end
end