//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 }