Skip to content

Instantly share code, notes, and snippets.

@skymonsters-Ks
Last active February 8, 2020 14:57
Show Gist options
  • Save skymonsters-Ks/ccea0d954992cc5be23672ce72931593 to your computer and use it in GitHub Desktop.
Save skymonsters-Ks/ccea0d954992cc5be23672ce72931593 to your computer and use it in GitHub Desktop.
ウィンドウとフルスクリーンの切替
; #include "hgimg4.as" ; HGIMG4 は HSP3.6b2 以降
#include "user32.as"
#module
#const GWL_STYLE -16
#const WS_POPUP $80000000
#const WS_VISIBLE $10000000
#const WM_KILLFOCUS $8
#const WM_GETMINMAXINFO $24
#const WM_WINDOWPOSCHANGED $47
#const SM_CMONITORS 80
#const HWND_NOTOPMOST -2
#const HWND_TOPMOST -1
#const SWP_FRAMECHANGED $20
#const SWP_SHOWWINDOW $40
#const CDS_TEST $2
#const CDS_FULLSCREEN $4
#const ENUM_CURRENT_SETTINGS -1
#const MONITOR_DEFAULTTONEAREST 2
; モジュール初期化
; 対象ウィンドウが選択された状態で呼び出して
; 内で oncmd いくつか使っているので重複注意
#deffunc fw_init
dim dmode, 40 ; DEVMODE
dim minfo, 18 ; MONITORINFOEX
minfo = 72 ; cbSize
full = 0
mmw = ginfo_sizex
mmh = ginfo_sizey
oncmd gosub *wmGetMinMaxInfo, WM_GETMINMAXINFO
oncmd gosub *wmWindowPosChanged, WM_WINDOWPOSCHANGED
oncmd gosub *wmKillFocus, WM_KILLFOCUS
return
; ウィンドウサイズ上限解除とモニター間移動時のリサイズ防止
*wmGetMinMaxInfo
dupptr mmi, lparam + 24, 16 ; MINMAXINFO ptMinTrackSize, ptMaxTrackSize
mmi = mmw, mmh, mmw, mmh
return 0
; フルスクリーンモードでウィンドウ移動が起こったとき用
; 本当はモニター間移動時のメッセージとかがほしい…
*wmWindowPosChanged
if full {
dupptr wp, lparam, 28 ; WINDOWPOS
if wp(2) != monix || wp(3) != moniy {
winx = wp(2)
winy = wp(3)
fw_change 0
fw_change 1
}
}
return 0
; フルスクリーンモードでフォーカス失ったとき用
; シングルモニタ環境下ではフルスクリーン解除した方がいいと思う
*wmKillFocus
if full : if GetSystemMetrics(SM_CMONITORS) == 1 : fw_change 0
return 0
; モード変更。0 でウィンドウモード、1 でフルスクリーンモードに。stat 0 で変更成功、1 で失敗。
#deffunc fw_change int _m, local _mh
if _m {
if full == 1 : return 1
winx = ginfo_wx1
winy = ginfo_wy1
winw = ginfo_sizex
winh = ginfo_sizey
winstyle = GetWindowLong(hwnd, GWL_STYLE)
_mh = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST)
mname = getMoniName(_mh)
chgDispEx mname, ginfo_sx, ginfo_sy
if stat : return 1
mmw = ginfo_sx
mmh = ginfo_sy
getMoniPos monix, moniy, _mh
chgWin HWND_TOPMOST, monix, moniy, mmw, mmh, WS_POPUP | WS_VISIBLE
full = 1
} else {
if full == 0 : return 1
mmw = winw
mmh = winh
full = 0 ; 直後の chgDispEx, chgWin で何度かウィンドウメッセージが来て wmWindowPosChanged を通過するので先に変更しておく
chgDispEx mname
chgWin HWND_NOTOPMOST, winx, winy, winw, winh, winstyle
}
return 0
; モード取得。0 ウィンドウモード、1 フルスクリーンモード
#defcfunc fw_stat
return full
#deffunc local chgWin int _z, int _x, int _y, int _w, int _h, int _s
SetWindowLong hwnd, GWL_STYLE, _s
SetWindowPos hwnd, _z, _x, _y, _w, _h, SWP_FRAMECHANGED | SWP_SHOWWINDOW
return
#defcfunc local getMoniName int _mh, local _mn
GetMonitorInfo _mh, varptr(minfo)
getstr _mn, minfo, 40 ; szDevice
return _mn
#deffunc local getMoniPos var _x, var _y, int _mh
GetMonitorInfo _mh, varptr(minfo)
_x = minfo(1)
_y = minfo(2)
return
; 指定デバイスモードが対応しているかを取得。0 対応、1 未対応
#defcfunc local chkDisp str _name, int _w, int _h, int _fr
EnumDisplaySettings _name, ENUM_CURRENT_SETTINGS, varptr(dmode)
dmode(27) = _w ; dmPelsWidth
dmode(28) = _h ; dmPelsHeight
if _fr > 0 {
dmode(30) = _fr ; dmDisplayFrequency
}
ChangeDisplaySettingsEx _name, varptr(dmode), 0, CDS_TEST, 0
return stat < 0
; デバイスモード変更。_w に 0 指定でモードを戻す。stat 0 で成功、1 で失敗
#deffunc local chgDispEx str _name, int _w, int _h, int _fr
if _w > 0 {
if chkDisp(_name, _w, _h, _fr) : return 1
ChangeDisplaySettingsEx _name, varptr(dmode), 0, CDS_FULLSCREEN, 0
} else {
ChangeDisplaySettingsEx _name, 0, 0, CDS_FULLSCREEN, 0
}
return 0
#global
screen 0, 800, 600
#ifdef _HGIMG4
gpreset
#endif
fw_init
sx = ginfo_sx
sy = ginfo_sy
px = sx / 2
py = sy / 2
vx = 3
vy = 3
sz = 200
szh = sz / 2
*mainLoop
gosub *checkKey
gosub *move
gosub *draw
await 15
goto *mainLoop
*checkKey
stick key
if key & 128 : end ; [Esc]
if key & 32 { ; [Enter]
fw_change fw_stat() ^ 1
if stat {
ffc = 200
}
}
return
*move
px += vx
py += vy
if px < szh : px = sz - px : vx = -vx
if py < szh : py = sz - py : vy = -vy
if px > sx - szh : px = 2 * (sx - szh) - px : vx = -vx
if py > sy - szh : py = 2 * (sy - szh) - py : vy = -vy
return
*draw
redraw 0
color 50, 0, 100
boxf
color 250, 50, 150
grect px, py, 0, sz, sz
line rnd(sx), sy, rnd(sx), 0
pos 10, 10
color 200, 200, 200
if fw_stat() {
mes "Fullscreen Mode"
} else {
mes "Window Mode"
}
if ffc {
mes strf("[%dx%d] incompatible mode", sx, sy)
ffc--
}
redraw 1
return
; #include "hgimg4.as" ; HGIMG4 は HSP3.6b2 以降
#include "user32.as"
#include "gdi32.as"
#module
#const GWL_STYLE -16
#const BLACK_BRUSH 4
#const WS_POPUP $80000000
#const WS_VISIBLE $10000000
#const SRCCOPY $00cc0020
#const WM_KILLFOCUS $8
#const WM_GETMINMAXINFO $24
#const WM_WINDOWPOSCHANGED $47
#const SM_CMONITORS 80
#const HWND_NOTOPMOST -2
#const HWND_TOPMOST -1
#const SWP_FRAMECHANGED $20
#const SWP_SHOWWINDOW $40
#const MONITOR_DEFAULTTONEAREST 2
; モジュール初期化
; 対象ウィンドウが選択された状態で呼び出して
; 内で oncmd いくつか使っているので重複注意
; HGIMG4 使用時は _id にモジュール内で使うウィンドウID指定可、省略すると呼び出し時点での未使用IDを使用、stat にIDが返る
#deffunc fw_init int _id
dim point, 2 ; POINT
dim minfo, 18 ; MONITORINFOEX
minfo = 72 ; cbSize
rate = 100
full = 0
destw = ginfo_sx
desth = ginfo_sy
mmw = ginfo_sizex
mmh = ginfo_sizey
ncw = mmw - destw
nch = mmh - desth
#ifdef _HGIMG4
winid = ginfo_sel
if _id <= 0 {
bufid = ginfo_newid
} else {
bufid = _id
}
buffer bufid, destw, desth, screen_offscreen
gsel winid
setcls 1, $000000
#else
bufid = ginfo_sel
#endif
oncmd gosub *wmGetMinMaxInfo, WM_GETMINMAXINFO
oncmd gosub *wmWindowPosChanged, WM_WINDOWPOSCHANGED
oncmd gosub *wmKillFocus, WM_KILLFOCUS
return bufid
; ウィンドウサイズ上限解除とモニター間移動時のリサイズ防止
*wmGetMinMaxInfo
dupptr mmi, lparam + 24, 16 ; MINMAXINFO ptMinTrackSize, ptMaxTrackSize
mmi = mmw, mmh, mmw, mmh
return 0
; フルスクリーンモードでウィンドウ移動が起こったとき用
; 本当はモニター間移動時のメッセージとかがほしい…
*wmWindowPosChanged
if full {
dupptr wp, lparam, 28 ; WINDOWPOS
if wp(2) != monix || wp(3) != moniy {
winx = wp(2)
winy = wp(3)
fw_change 0
fw_change 1
}
}
return 0
; フルスクリーンモードでフォーカス失ったとき用
; シングルモニタ環境下ではフルスクリーン解除した方がいいと思う
*wmKillFocus
if full : if GetSystemMetrics(SM_CMONITORS) == 1 : fw_change 0
return 0
; redraw の代わりに使用する(メイン画面のみ)、buffer で作成したウィンドウIDには通常通り redraw を使用する。
; パラメータ省略時は挙動が違うので注意
#deffunc fw_redraw int _m, local _dc
#ifdef _HGIMG4
if full || rate != 100 {
if _m {
redraw 1
gsel winid
redraw 0
gpviewport destx, desty, destw, desth
gmode 0
gmulcolor
pos 0, 0
celput bufid
redraw 1
} else {
gsel bufid
redraw 0
gpviewport 0, 0, ginfo_sx, ginfo_sy
; gfilter 1
}
} else {
redraw _m
gpviewport 0, 0, ginfo_sx, ginfo_sy
}
#else
if full || rate != 100 {
if _m {
_dc = GetDC(hwnd)
StretchBlt _dc, destx, desty, destw, desth, hdc, 0, 0, ginfo_sx, ginfo_sy, SRCCOPY
ReleaseDC hwnd, _dc
} else {
redraw 0
}
} else {
redraw _m
}
#endif
return
; モード変更。0 でウィンドウモード、1 でフルスクリーンモードに
#deffunc fw_change int _m, local _mh, local _dc
if _m {
if full == 1 : return
winx = ginfo_wx1
winy = ginfo_wy1
winw = ginfo_sizex
winh = ginfo_sizey
winstyle = GetWindowLong(hwnd, GWL_STYLE)
_mh = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST)
getMoniPos monix, moniy, _mh
getMoniSize mmw, mmh, _mh
; スクリーンを中央に配置するための計算
if mmw * ginfo_sy < mmh * ginfo_sx {
destw = mmw
desth = mmw * ginfo_sy / ginfo_sx
destx = 0
desty = (mmh - desth) / 2
} else {
destw = mmh * ginfo_sx / ginfo_sy
desth = mmh
destx = (mmw - destw) / 2
desty = 0
}
chgWin HWND_TOPMOST, monix, moniy, mmw, mmh, WS_POPUP | WS_VISIBLE
full = 1
} else {
if full == 0 : return
destx = 0
desty = 0
destw = ginfo_sx * rate / 100
desth = ginfo_sy * rate / 100
mmw = winw
mmh = winh
full = 0 ; 直後の chgWin でウィンドウメッセージが来て wmWindowPosChanged を通過するので先に変更しておく
chgWin HWND_NOTOPMOST, winx, winy, winw, winh, winstyle
}
#ifndef _HGIMG4
; '画面外' の塗りつぶしとHSPバッファのちらつき低減
ValidateRect hwnd, 0
color : boxf : redraw 1
_dc = GetDC(hwnd)
SelectObject _dc, GetStockObject(BLACK_BRUSH)
Rectangle _dc, 0, 0, mmw, mmh
ReleaseDC hwnd, _dc
#endif
return
; スクリーンリサイズ、_r は%指定、100 でオリジナル倍率
#deffunc fw_resize int _r
if full == 0 {
if _r < 10 {
rate = 10
} else {
rate = _r
}
destx = 0
desty = 0
destw = ginfo_sx * rate / 100
desth = ginfo_sy * rate / 100
mmw = destw + ncw
mmh = desth + nch
winx = ginfo_wx1
winy = ginfo_wy1
chgWin HWND_NOTOPMOST, winx, winy, mmw, mmh, GetWindowLong(hwnd, GWL_STYLE)
#ifndef _HGIMG4
ValidateRect hwnd, 0
color : boxf : redraw 1
#endif
}
return
; 状態取得
#defcfunc fw_stat int _m
switch _m
case 1 : return rate ; スクリーン倍率
case 2 : return destw ; スクリーン幅
case 3 : return desth ; スクリーン高さ
swend
return full ; 0 ウィンドウモード、1 フルスクリーンモード
#defcfunc fw_mousex
GetCursorPos varptr(point)
ScreenToClient hwnd, varptr(point)
return limit((point(0) - destx) * ginfo_sx / destw, 0, ginfo_sx - 1)
#defcfunc fw_mousey
GetCursorPos varptr(point)
ScreenToClient hwnd, varptr(point)
return limit((point(1) - desty) * ginfo_sy / desth, 0, ginfo_sy - 1)
#undef mousex
#define global mousex fw_mousex()
#undef mousey
#define global mousey fw_mousey()
#deffunc local chgWin int _z, int _x, int _y, int _w, int _h, int _s
SetWindowLong hwnd, GWL_STYLE, _s
SetWindowPos hwnd, _z, _x, _y, _w, _h, SWP_FRAMECHANGED | SWP_SHOWWINDOW
return
#deffunc local getMoniPos var _x, var _y, int _mh
GetMonitorInfo _mh, varptr(minfo)
_x = minfo(1)
_y = minfo(2)
return
#deffunc local getMoniSize var _w, var _h, int _mh
GetMonitorInfo _mh, varptr(minfo)
_w = minfo(3) - minfo(1)
_h = minfo(4) - minfo(2)
return
#global
; screen 0, 256, 240
#ifdef _HGIMG4
gpreset
#endif
fw_init ; HGIMG4 使用時は buffer, celload など他で使用しない0以外のウィンドウIDを指定する
sx = ginfo_sx
sy = ginfo_sy
px = sx / 2
py = sy / 2
vx = 3
vy = 3
sz = 200
szh = sz / 2
*mainLoop
gosub *checkKey
gosub *move
gosub *draw
await 15
goto *mainLoop
*checkKey
stick key
if key & 128 : end ; [Esc]
if key & 32 : fw_change fw_stat() ^ 1 ; [Enter]
if key & 1 : fw_resize fw_stat(1) - 10 ; [left]
if key & 4 : fw_resize fw_stat(1) + 10 ; [right]
if key & 2 : fw_resize fw_stat(1) + 100 ; [up]
if key & 8 : fw_resize fw_stat(1) - 100 ; [down]
return
*move
px += vx
py += vy
if px < szh : px = sz - px : vx = -vx
if py < szh : py = sz - py : vy = -vy
if px > sx - szh : px = 2 * (sx - szh) - px : vx = -vx
if py > sy - szh : py = 2 * (sy - szh) - py : vy = -vy
return
*draw
fw_redraw 0
color 50, 0, 100
boxf
color 250, 50, 150
grect px, py, 0, sz, sz
line rnd(sx), sy, rnd(sx), 0
pos 10, 10
color 200, 200, 200
if fw_stat() {
mes "Fullscreen Mode"
} else {
mes "Window Mode"
mes strf("Size: %dx%d (%d%%)", fw_stat(2), fw_stat(3), fw_stat(1))
}
mes strf("Mouse X:%d, Y:%d", mousex, mousey)
fw_redraw 1
return
@skymonsters-Ks
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment