108 lines
2.4 KiB
Go
108 lines
2.4 KiB
Go
//go:build windows
|
|
|
|
package cell_size
|
|
|
|
import (
|
|
"fmt"
|
|
"syscall"
|
|
"unsafe"
|
|
|
|
"golang.org/x/sys/windows"
|
|
)
|
|
|
|
type coord struct {
|
|
X int16
|
|
Y int16
|
|
}
|
|
|
|
type consoleFontInfoEx struct {
|
|
cbSize uint32
|
|
nFont uint32
|
|
dwFontSize coord
|
|
fontFamily uint32
|
|
fontWeight uint32
|
|
faceName [32]uint16
|
|
}
|
|
|
|
var (
|
|
kernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
|
procGetCurrentConsoleFontEx = kernel32.NewProc("GetCurrentConsoleFontEx")
|
|
)
|
|
|
|
func GetTerminalCellSizePixels() (widthPx int, heightPx int, err error) {
|
|
var fontInfo consoleFontInfoEx
|
|
fontInfo.cbSize = uint32(unsafe.Sizeof(fontInfo))
|
|
|
|
stdOutHandle := windows.Handle(syscall.Stdout)
|
|
ret, _, err := procGetCurrentConsoleFontEx.Call(
|
|
uintptr(stdOutHandle),
|
|
uintptr(0), // bMaximumWindow = false
|
|
uintptr(unsafe.Pointer(&fontInfo)),
|
|
)
|
|
if ret == 0 {
|
|
return 0, 0, err
|
|
}
|
|
return int(fontInfo.dwFontSize.X), int(fontInfo.dwFontSize.Y), nil
|
|
}
|
|
|
|
type (
|
|
short int16
|
|
word uint16
|
|
smallRect struct {
|
|
Left short
|
|
Top short
|
|
Right short
|
|
Bottom short
|
|
}
|
|
consoleScreenBufferInfo struct {
|
|
Size coord
|
|
CursorPosition coord
|
|
Attributes word
|
|
Window smallRect
|
|
MaximumWindowSize coord
|
|
}
|
|
)
|
|
|
|
var kernel32DLL = syscall.NewLazyDLL("kernel32.dll")
|
|
var getConsoleScreenBufferInfoProc = kernel32DLL.NewProc("GetConsoleScreenBufferInfo")
|
|
|
|
// GetConsoleSize returns the current number of columns and rows in the active console window.
|
|
// The return value of this function is in the order of cols, rows.
|
|
func GetConsoleSize() (int, int) {
|
|
stdoutHandle := getStdHandle(syscall.STD_OUTPUT_HANDLE)
|
|
var info, err = getConsoleScreenBufferInfo(stdoutHandle)
|
|
|
|
if err != nil {
|
|
return 0, 0
|
|
}
|
|
|
|
return int(info.Window.Right - info.Window.Left + 1), int(info.Window.Bottom - info.Window.Top + 1)
|
|
}
|
|
|
|
func getError(r1, r2 uintptr, lastErr error) error {
|
|
// If the function fails, the return value is zero.
|
|
if r1 == 0 {
|
|
if lastErr != nil {
|
|
return lastErr
|
|
}
|
|
return syscall.EINVAL
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func getStdHandle(stdhandle int) uintptr {
|
|
handle, err := syscall.GetStdHandle(stdhandle)
|
|
if err != nil {
|
|
panic(fmt.Errorf("could not get standard io handle %d", stdhandle))
|
|
}
|
|
return uintptr(handle)
|
|
}
|
|
|
|
func getConsoleScreenBufferInfo(handle uintptr) (*consoleScreenBufferInfo, error) {
|
|
var info consoleScreenBufferInfo
|
|
if err := getError(getConsoleScreenBufferInfoProc.Call(handle, uintptr(unsafe.Pointer(&info)), 0)); err != nil {
|
|
return nil, err
|
|
}
|
|
return &info, nil
|
|
}
|