접기#============================================================================== # ★ Fullscreen++ Multi-Monitor Edition v2.33 for RPG Maker VX # F12 재시작 후 검은 배경 고정 버그 완전 수정 # F5 = 전체화면 토글 F6 = 창 모드 배율 변경 #==============================================================================
$imported ||= {} $imported[:Zeus_Fullscreen_MultiMonitor_VX] = true
class << Graphics Disable_VX_Fullscreen = true # true = Alt+Enter 기본 전체화면 비활성화
# Win32API 정의 unless defined?(CreateWindowEx) CreateWindowEx = Win32API.new('user32', 'CreateWindowEx', 'ippiiiiiiiii', 'i') GetClientRect = Win32API.new('user32', 'GetClientRect', 'ip', 'i') GetDC = Win32API.new('user32', 'GetDC', 'i', 'i') GetWindowRect = Win32API.new('user32', 'GetWindowRect', 'ip', 'i') FillRect = Win32API.new('user32', 'FillRect', 'ipi', 'i') FindWindow = Win32API.new('user32', 'FindWindow', 'pp', 'i') ReleaseDC = Win32API.new('user32', 'ReleaseDC', 'ii', 'i') SendInput = Win32API.new('user32', 'SendInput', 'ipi', 'i') SetWindowLong = Win32API.new('user32', 'SetWindowLong', 'iii', 'i') SetWindowPos = Win32API.new('user32', 'SetWindowPos', 'iiiiiii', 'i') ShowWindow = Win32API.new('user32', 'ShowWindow', 'ii', 'i') UpdateWindow = Win32API.new('user32', 'UpdateWindow', 'i', 'i') DestroyWindow = Win32API.new('user32', 'DestroyWindow', 'i', 'i') # ← 추가 GetPrivateProfileString = Win32API.new('kernel32', 'GetPrivateProfileString', 'ppppip', 'i') WritePrivateProfileString = Win32API.new('kernel32', 'WritePrivateProfileString', 'pppp', 'i') CreateSolidBrush = Win32API.new('gdi32', 'CreateSolidBrush', 'i', 'i') DeleteObject = Win32API.new('gdi32', 'DeleteObject', 'i', 'i')
MonitorFromRect = Win32API.new('user32', 'MonitorFromRect', 'pi', 'i') GetMonitorInfoA = Win32API.new('user32', 'GetMonitorInfoA', 'lp', 'i') end
HWND = FindWindow.call('RGSS Player', 0) # BackHWND를 변수로 관리 (재시작 대비) @back_hwnd = nil
def back_hwnd return @back_hwnd if @back_hwnd && @back_hwnd != 0 @back_hwnd = CreateWindowEx.call(0x08000008, 'Static', '', 0x80000000, 0, 0, 0, 0, 0, 0, 0, 0) @back_hwnd end
def destroy_back_hwnd if @back_hwnd && @back_hwnd != 0 ShowWindow.call(@back_hwnd, 0) DestroyWindow.call(@back_hwnd) @back_hwnd = nil end end
unless method_defined?(:zeus_fullscreen_update) alias zeus_fullscreen_resize_screen resize_screen alias zeus_fullscreen_update update end
#========================================================================== # ● 현재 모니터 정보 #========================================================================== def current_monitor_info rect_buf = " " * 4 GetWindowRect.call(HWND, rect_buf) left, top, right, bottom = rect_buf.unpack('l4') rect_struct = [left, top, right, bottom].pack('l4')
hmonitor = MonitorFromRect.call(rect_struct, 2)
mi = [40, 0,0,0,0, 0,0,0,0, 0,0,0,0].pack('l*') + "\0"*32 GetMonitorInfoA.call(hmonitor, mi)
mon_l, mon_t, mon_r, mon_b = mi[4, 16].unpack('l4') work_l, work_t, work_r, work_b = mi[20, 16].unpack('l4')
{ :full_rect => Rect.new(mon_l, mon_t, mon_r - mon_l, mon_b - mon_t), :work_rect => Rect.new(work_l, work_t, work_r - work_l, work_b - work_t) } end
private def initialize_fullscreen_rects @borders_size ||= borders_size info = current_monitor_info @fullscreen_rect = info[:full_rect] @workarea_rect = info[:work_rect] end
def borders_size GetWindowRect.call(HWND, wrect = [0,0,0,0].pack('l4')) GetClientRect.call(HWND, crect = [0,0,0,0].pack('l4')) w = wrect.unpack('l4') c = crect.unpack('l4') Rect.new(0, 0, w[2]-w[0]-c[2], w[3]-w[1]-c[3]) end
def position_back_window return unless @fullscreen && @fullscreen_rect info = current_monitor_info x, y = info[:full_rect].x, info[:full_rect].y w, h = info[:full_rect].width, info[:full_rect].height SetWindowPos.call(back_hwnd, HWND, x, y, w, h, 0x0004) # HWND_TOP end
def hide_borders() SetWindowLong.call(HWND, -16, 0x14000000) end def show_borders() SetWindowLong.call(HWND, -16, 0x14CA0000) end
def hide_back ShowWindow.call(back_hwnd, 0) if @back_hwnd end
def show_back initialize_fullscreen_rects hwnd = back_hwnd ShowWindow.call(hwnd, 3) # SW_SHOWMAXIMIZED UpdateWindow.call(hwnd) dc = GetDC.call(hwnd) rect = [0, 0, @fullscreen_rect.width, @fullscreen_rect.height].pack('l4') brush = CreateSolidBrush.call(0) # black FillRect.call(dc, rect, brush) ReleaseDC.call(hwnd, dc) DeleteObject.call(brush)
position_back_window end
def resize_window(w, h) initialize_fullscreen_rects
if @fullscreen x = @fullscreen_rect.x + (@fullscreen_rect.width - w) / 2 y = @fullscreen_rect.y + (@fullscreen_rect.height - h) / 2 z = -1 position_back_window else w += @borders_size.width h += @borders_size.height x = @workarea_rect.x + (@workarea_rect.width - w) / 2 y = @workarea_rect.y + (@workarea_rect.height - h) / 2 z = -2 hide_back() end SetWindowPos.call(HWND, z, x.to_i, y.to_i, w.to_i, h.to_i, 0) end
def release_alt inputs = [1,18,2, 1,164,2, 1,165,2].pack('LSx2Lx16'*3) SendInput.call(3, inputs, 28) end
public def load_fullscreen_settings # F12 재시작 시 이전 백그라운드 완전 제거 destroy_back_hwnd if @fullscreen == nil # 처음 로드될 때만 강제 정리
buffer = [].pack('x256') section = 'Fullscreen++' filename = './Game.ini' get_option = Proc.new do |key, default| l = GetPrivateProfileString.call(section, key, default.to_s, buffer, buffer.size, filename) buffer[0, l] end
@fullscreen = get_option.call('Fullscreen', '0') == '1' @fullscreen_ratio = get_option.call('FullscreenRatio', '0').to_i @windowed_ratio = get_option.call('WindowedRatio', '1').to_i
toggle_vx_fullscreen if Disable_VX_Fullscreen && vx_fullscreen? # 강제 초기화 @fullscreen = false windowed_mode end
def save_fullscreen_settings section = 'Fullscreen++' filename = './Game.ini' set = Proc.new { |k, v| WritePrivateProfileString.call(section, k, v.to_s, filename) } set.call('Fullscreen', @fullscreen ? 1 : 0) set.call('FullscreenRatio', @fullscreen_ratio) set.call('WindowedRatio', @windowed_ratio) end
def fullscreen?; @fullscreen || vx_fullscreen?; end
def vx_fullscreen? @fullscreen_rect && @fullscreen_rect.width == 640 && @fullscreen_rect.height == 480 end
def toggle_fullscreen fullscreen? ? windowed_mode : fullscreen_mode end
def fullscreen_mode return if vx_fullscreen? @fullscreen = true show_back hide_borders self.ratio += 0 save_fullscreen_settings end
def windowed_mode toggle_vx_fullscreen if vx_fullscreen? @fullscreen = false hide_back show_borders self.ratio += 0 save_fullscreen_settings end
def toggle_ratio return if vx_fullscreen? self.ratio += 1 end
def ratio return 1 if vx_fullscreen? @fullscreen ? @fullscreen_ratio : @windowed_ratio end
def ratio=(r) return if vx_fullscreen? initialize_fullscreen_rects r = 0 if r < 0
if @fullscreen @fullscreen_ratio = r w_max = @fullscreen_rect.width h_max = @fullscreen_rect.height else @windowed_ratio = r w_max = @workarea_rect.width - @borders_size.width h_max = @workarea_rect.height - @borders_size.height end
if r == 0 w = w_max h = (w_max * height.to_f / width).to_i if h > h_max h = h_max w = (h_max * width.to_f / height).to_i end else w = width * r h = height * r return self.ratio = 0 if w > w_max || h > h_max end
resize_window(w, h) save_fullscreen_settings end
def update release_alt if Disable_VX_Fullscreen && Input.trigger?(Input::ALT) zeus_fullscreen_update toggle_fullscreen if Input.trigger?(Input::F5) toggle_ratio if Input.trigger?(Input::F6) end
def resize_screen(width, height) zeus_fullscreen_resize_screen(width, height) self.ratio += 0 end end
# 시작 시 초기화 Graphics.load_fullscreen_settings |
접기#============================================================================== # ★ Fullscreen++ Multi-Monitor Edition v2.32 # 멀티모니터에서 검은 배경도 정확히 현재 모니터에만 적용 # F5 = 전체화면 토글 F6 = 창 모드 배율 변경 #==============================================================================
$imported ||= {} $imported[:Zeus_Fullscreen_MultiMonitor] = true
class << Graphics Disable_VX_Fullscreen = false
# Win32API (중복 방지) unless defined?(CreateWindowEx) CreateWindowEx = Win32API.new('user32', 'CreateWindowEx', 'ippiiiiiiiii', 'i') GetClientRect = Win32API.new('user32', 'GetClientRect', 'ip', 'i') GetDC = Win32API.new('user32', 'GetDC', 'i', 'i') GetSystemMetrics = Win32API.new('user32', 'GetSystemMetrics', 'i', 'i') GetWindowRect = Win32API.new('user32', 'GetWindowRect', 'ip', 'i') FillRect = Win32API.new('user32', 'FillRect', 'ipi', 'i') FindWindow = Win32API.new('user32', 'FindWindow', 'pp', 'i') ReleaseDC = Win32API.new('user32', 'ReleaseDC', 'ii', 'i') SendInput = Win32API.new('user32', 'SendInput', 'ipi', 'i') SetWindowLong = Win32API.new('user32', 'SetWindowLong', 'iii', 'i') SetWindowPos = Win32API.new('user32', 'SetWindowPos', 'iiiiiii', 'i') ShowWindow = Win32API.new('user32', 'ShowWindow', 'ii', 'i') SystemParametersInfo = Win32API.new('user32', 'SystemParametersInfo', 'iipi', 'i') UpdateWindow = Win32API.new('user32', 'UpdateWindow', 'i', 'i') GetPrivateProfileString = Win32API.new('kernel32', 'GetPrivateProfileString', 'ppppip', 'i') WritePrivateProfileString = Win32API.new('kernel32', 'WritePrivateProfileString', 'pppp', 'i') CreateSolidBrush = Win32API.new('gdi32', 'CreateSolidBrush', 'i', 'i') DeleteObject = Win32API.new('gdi32', 'DeleteObject', 'i', 'i')
MonitorFromRect = Win32API.new('user32', 'MonitorFromRect', 'pi', 'i') GetMonitorInfoA = Win32API.new('user32', 'GetMonitorInfoA', 'lp', 'i') end
HWND = FindWindow.call('RGSS Player', 0) BackHWND = CreateWindowEx.call(0x08000008, 'Static', '', 0x80000000, 0, 0, 0, 0, 0, 0, 0, 0)
unless method_defined?(:zeus_fullscreen_update) alias zeus_fullscreen_resize_screen resize_screen alias zeus_fullscreen_update update end
#========================================================================== # ● 현재 모니터 정보 (full_rect = 전체화면용) #========================================================================== def current_monitor_info rect_buf = " " * 4 GetWindowRect.call(HWND, rect_buf) left, top, right, bottom = rect_buf.unpack('l4') rect_struct = [left, top, right, bottom].pack('l4')
hmonitor = MonitorFromRect.call(rect_struct, 2)
mi = [40, 0,0,0,0, 0,0,0,0, 0,0,0,0].pack('l*') + "\0"*32 GetMonitorInfoA.call(hmonitor, mi)
mon_l, mon_t, mon_r, mon_b = mi[4, 16].unpack('l4') work_l, work_t, work_r, work_b = mi[20, 16].unpack('l4')
{ full_rect: Rect.new(mon_l, mon_t, mon_r - mon_l, mon_b - mon_t), work_rect: Rect.new(work_l, work_t, work_r - work_l, work_b - work_t) } end
private def initialize_fullscreen_rects @borders_size ||= borders_size info = current_monitor_info @fullscreen_rect = info[:full_rect] @workarea_rect = info[:work_rect] end
def borders_size GetWindowRect.call(HWND, wrect = [0,0,0,0].pack('l4')) GetClientRect.call(HWND, crect = [0,0,0,0].pack('l4')) w = wrect.unpack('l4') c = crect.unpack('l4') Rect.new(0, 0, w[2]-w[0]-c[2], w[3]-w[1]-c[3]) end
# ★★★ 핵심 수정: BackHWND를 현재 모니터 전체로 정확히 이동 ★★★ def position_back_window return unless @fullscreen && @fullscreen_rect info = current_monitor_info x, y = info[:full_rect].x, info[:full_rect].y w, h = info[:full_rect].width, info[:full_rect].height
# BackHWND를 현재 모니터 전체 영역으로 이동 + 크기 조정 SetWindowPos.call(BackHWND, HWND, x, y, w, h, 0x0004) # SWP_NOZORDER + SWP_NOACTIVATE end
def hide_borders() SetWindowLong.call(HWND, -16, 0x14000000) end def show_borders() SetWindowLong.call(HWND, -16, 0x14CA0000) end def hide_back() ShowWindow.call(BackHWND, 0) end
def show_back ShowWindow.call(BackHWND, 3) UpdateWindow.call(BackHWND) dc = GetDC.call(BackHWND) rect = [0, 0, @fullscreen_rect.width, @fullscreen_rect.height].pack('l4') brush = CreateSolidBrush.call(0) # 검은색 브러시 FillRect.call(dc, rect, brush) ReleaseDC.call(BackHWND, dc) DeleteObject.call(brush)
position_back_window # ← 여기서 위치 보정 end
def resize_window(w, h) info = current_monitor_info @fullscreen_rect = info[:full_rect] @workarea_rect = info[:work_rect]
if @fullscreen x = @fullscreen_rect.x + (@fullscreen_rect.width - w) / 2 y = @fullscreen_rect.y + (@fullscreen_rect.height - h) / 2 z = -1 position_back_window # 전체화면일 때 BackHWND도 다시 위치 else w += @borders_size.width h += @borders_size.height x = @workarea_rect.x + (@workarea_rect.width - w) / 2 y = @workarea_rect.y + (@workarea_rect.height - h) / 2 z = -2 hide_back() end SetWindowPos.call(HWND, z, x.to_i, y.to_i, w.to_i, h.to_i, 0) end
def release_alt inputs = [1,18,2, 1,164,2, 1,165,2].pack('LSx2Lx16'*3) SendInput.call(3, inputs, 28) end
public def load_fullscreen_settings buffer = [].pack('x256') section = 'Fullscreen++' filename = './Game.ini' get_option = Proc.new do |key, default| l = GetPrivateProfileString.call(section, key, default.to_s, buffer, buffer.size, filename) buffer[0, l] end @fullscreen = get_option.call('Fullscreen', '0') == '1' @fullscreen_ratio = get_option.call('FullscreenRatio', '0').to_i @windowed_ratio = get_option.call('WindowedRatio', '1').to_i
toggle_vx_fullscreen if Disable_VX_Fullscreen && vx_fullscreen? fullscreen? ? fullscreen_mode : windowed_mode end
def save_fullscreen_settings section = 'Fullscreen++' filename = './Game.ini' set = Proc.new { |k, v| WritePrivateProfileString.call(section, k, v.to_s, filename) } set.call('Fullscreen', @fullscreen ? 1 : 0) set.call('FullscreenRatio', @fullscreen_ratio) set.call('WindowedRatio', @windowed_ratio) end
def fullscreen?; @fullscreen || vx_fullscreen?; end def vx_fullscreen? @fullscreen_rect && @fullscreen_rect.width == 640 && @fullscreen_rect.height == 480 end
def toggle_fullscreen fullscreen? ? windowed_mode : fullscreen_mode end
def toggle_vx_fullscreen windowed_mode if @fullscreen && !vx_fullscreen? inputs = [1,18,0, 1,13,0, 1,13,2, 1,18,2].pack('LSx2Lx16'*4) SendInput.call(4, inputs, 28) zeus_fullscreen_update self.ratio += 0 end
def fullscreen_mode return if vx_fullscreen? initialize_fullscreen_rects show_back hide_borders @fullscreen = true self.ratio += 0 end
def windowed_mode toggle_vx_fullscreen if vx_fullscreen? initialize_fullscreen_rects hide_back show_borders @fullscreen = false self.ratio += 0 end
def toggle_ratio return if vx_fullscreen? self.ratio += 1 end
def ratio return 1 if vx_fullscreen? @fullscreen ? @fullscreen_ratio : @windowed_ratio end
def ratio=(r) return if vx_fullscreen? initialize_fullscreen_rects r = 0 if r < 0
if @fullscreen @fullscreen_ratio = r w_max = @fullscreen_rect.width h_max = @fullscreen_rect.height else @windowed_ratio = r w_max = @workarea_rect.width - @borders_size.width h_max = @workarea_rect.height - @borders_size.height end
if r == 0 w = w_max h = (w_max * height.to_f / width).to_i if h > h_max h = h_max w = (h_max * width.to_f / height).to_i end else w = width * r h = height * r return self.ratio = 0 if w > w_max || h > h_max end
resize_window(w, h) save_fullscreen_settings end
def update release_alt if Disable_VX_Fullscreen && Input.trigger?(Input::ALT) zeus_fullscreen_update toggle_fullscreen if Input.trigger?(Input::F5) toggle_ratio if Input.trigger?(Input::F6) end
def resize_screen(width, height) zeus_fullscreen_resize_screen(width, height) self.ratio += 0 end end
Graphics.load_fullscreen_settings p "OK: Fullscreen++ Multi-Monitor v2.32 (검은 배경 멀티모니터 완전 수정)" |