mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-26 11:48:55 +01:00
devicescale: Get the current monitor's scale on Windows (#644)
This commit is contained in:
parent
c494b53822
commit
399317a2cf
@ -19,22 +19,45 @@ package devicescale
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
const logPixelSx = 88
|
const (
|
||||||
|
logPixelSx = 88
|
||||||
|
monitorDefaultToNearest = 2
|
||||||
|
mdtEffectiveDpi = 0
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
user32 = syscall.NewLazyDLL("user32")
|
user32 = syscall.NewLazyDLL("user32")
|
||||||
gdi32 = syscall.NewLazyDLL("gdi32")
|
gdi32 = syscall.NewLazyDLL("gdi32")
|
||||||
|
shcore = syscall.NewLazyDLL("shcore")
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
procSetProcessDPIAware = user32.NewProc("SetProcessDPIAware")
|
procSetProcessDPIAware = user32.NewProc("SetProcessDPIAware")
|
||||||
|
procGetActiveWindow = user32.NewProc("GetActiveWindow")
|
||||||
procGetWindowDC = user32.NewProc("GetWindowDC")
|
procGetWindowDC = user32.NewProc("GetWindowDC")
|
||||||
procReleaseDC = user32.NewProc("ReleaseDC")
|
procReleaseDC = user32.NewProc("ReleaseDC")
|
||||||
|
procMonitorFromWindow = user32.NewProc("MonitorFromWindow")
|
||||||
|
procGetMonitorInfo = user32.NewProc("GetMonitorInfoW")
|
||||||
|
|
||||||
procGetDeviceCaps = gdi32.NewProc("GetDeviceCaps")
|
procGetDeviceCaps = gdi32.NewProc("GetDeviceCaps")
|
||||||
|
|
||||||
|
// GetScaleFactorForMonitor function can return unrelaiavle value (e.g. returning 180
|
||||||
|
// for 200% scale). Use GetDpiForMonitor instead.
|
||||||
|
procGetDpiForMonitor = shcore.NewProc("GetDpiForMonitor")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
var shcoreAvailable = false
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
if shcore.Load() == nil {
|
||||||
|
shcoreAvailable = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func setProcessDPIAware() error {
|
func setProcessDPIAware() error {
|
||||||
r, _, e := syscall.Syscall(procSetProcessDPIAware.Addr(), 0, 0, 0, 0)
|
r, _, e := syscall.Syscall(procSetProcessDPIAware.Addr(), 0, 0, 0, 0)
|
||||||
if e != 0 {
|
if e != 0 {
|
||||||
@ -46,6 +69,14 @@ func setProcessDPIAware() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getActiveWindow() (uintptr, error) {
|
||||||
|
r, _, e := syscall.Syscall(procGetActiveWindow.Addr(), 0, 0, 0, 0)
|
||||||
|
if e != 0 {
|
||||||
|
return 0, fmt.Errorf("devicescale: GetActiveWindow failed: error code: %d", e)
|
||||||
|
}
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
|
||||||
func getWindowDC(hwnd uintptr) (uintptr, error) {
|
func getWindowDC(hwnd uintptr) (uintptr, error) {
|
||||||
r, _, e := syscall.Syscall(procGetWindowDC.Addr(), 1, hwnd, 0, 0)
|
r, _, e := syscall.Syscall(procGetWindowDC.Addr(), 1, hwnd, 0, 0)
|
||||||
if e != 0 {
|
if e != 0 {
|
||||||
@ -76,22 +107,86 @@ func getDeviceCaps(hdc uintptr, nindex int) (int, error) {
|
|||||||
return int(r), nil
|
return int(r), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func impl() float64 {
|
func monitorFromWindow(hwnd uintptr, dwFlags int) (uintptr, error) {
|
||||||
if err := setProcessDPIAware(); err != nil {
|
r, _, e := syscall.Syscall(procMonitorFromWindow.Addr(), 2, hwnd, uintptr(dwFlags), 0)
|
||||||
panic(err)
|
if e != 0 {
|
||||||
|
return 0, fmt.Errorf("devicescale: MonitorFromWindow failed: error code: %d", e)
|
||||||
|
}
|
||||||
|
if r == 0 {
|
||||||
|
return 0, fmt.Errorf("devicescale: MonitorFromWindow failed: returned value: %d", r)
|
||||||
|
}
|
||||||
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getMonitorInfo(hMonitor uintptr, lpMonitorInfo uintptr) error {
|
||||||
|
r, _, e := syscall.Syscall(procGetMonitorInfo.Addr(), 2, hMonitor, lpMonitorInfo, 0)
|
||||||
|
if e != 0 {
|
||||||
|
return fmt.Errorf("devicescale: GetMonitorInfo failed: error code: %d", e)
|
||||||
|
}
|
||||||
|
if r == 0 {
|
||||||
|
return fmt.Errorf("devicescale: GetMonitorInfo failed: returned value: %d", r)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDpiForMonitor(hMonitor uintptr, dpiType uintptr, dpiX, dpiY uintptr) error {
|
||||||
|
r, _, e := syscall.Syscall6(procGetDpiForMonitor.Addr(), 4,
|
||||||
|
hMonitor, dpiType, dpiX, dpiY, 0, 0)
|
||||||
|
if e != 0 {
|
||||||
|
return fmt.Errorf("devicescale: GetDpiForMonitor failed: error code: %d", e)
|
||||||
|
}
|
||||||
|
if r != 0 {
|
||||||
|
return fmt.Errorf("devicescale: GetDpiForMonitor failed: returned value: %d", r)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getFromLogPixelSx() float64 {
|
||||||
dc, err := getWindowDC(0)
|
dc, err := getWindowDC(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
defer releaseDC(0, dc)
|
||||||
|
|
||||||
|
// Note that GetDeviceCaps with LOGPIXELSX always returns a same value for any monitors
|
||||||
|
// even if multiple monitors are used.
|
||||||
dpi, err := getDeviceCaps(dc, logPixelSx)
|
dpi, err := getDeviceCaps(dc, logPixelSx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
if err := releaseDC(0, dc); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return float64(dpi) / 96
|
return float64(dpi) / 96
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func impl() float64 {
|
||||||
|
if err := setProcessDPIAware(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// On Windows 7 or older, shcore.dll is not available.
|
||||||
|
if !shcoreAvailable {
|
||||||
|
return getFromLogPixelSx()
|
||||||
|
}
|
||||||
|
|
||||||
|
w, err := getActiveWindow()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
// The window is not initialized yet when w == 0.
|
||||||
|
if w == 0 {
|
||||||
|
return getFromLogPixelSx()
|
||||||
|
}
|
||||||
|
defer releaseDC(0, w)
|
||||||
|
|
||||||
|
m, err := monitorFromWindow(w, monitorDefaultToNearest)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dpiX := uint32(0)
|
||||||
|
dpiY := uint32(0) // Passing dpiY is needed even though this is not used.
|
||||||
|
if err := getDpiForMonitor(m, mdtEffectiveDpi, uintptr(unsafe.Pointer(&dpiX)), uintptr(unsafe.Pointer(&dpiY))); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return float64(dpiX) / 96
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user