magiblot / tvision

A modern port of Turbo Vision 2.0, the classical framework for text-based user interfaces. Now cross-platform and with Unicode support.
Other
2.04k stars 151 forks source link

Windows: automatically set TrueType font when raster font is configured? #48

Closed electroly closed 3 years ago

electroly commented 3 years ago

Not sure if this is appropriate for tvision to be doing; this might be something the client application should handle. I'm happy to ship this fix in the TMBASIC codebase but wanted to offer it to you in case tvision could use it.

Here is the code, please feel free to steal any or all of it if you're interested: https://github.com/electroly/tmbasic/blob/master/src/util/initConsole.cpp

I use GetCurrentConsoleFontEx to determine whether the console host is using a raster font, and if so, I use SetCurrentConsoleFontEx to change the font to either Consolas or Lucida Console. I check first to make sure the font is available on the system and bail if neither is present. Both fonts ship with the versions of Windows that tvision supports, but I wanted to err on the side of caution.

Doing this at startup allows TMBASIC to display correctly on a fresh Windows 7 install without the user needing to change their console settings. I haven't tested Vista but I imagine it will work the same there.

I had to link in -lgdi32 so I can use EnumFontFamiliesEx to check whether Consolas or Lucida Console are available.

magiblot commented 3 years ago

Although it's always best if the user can change the font settings to what they prefer, I'm a great advocate of making things work by default and preventing programmers from having to add workarounds (in particular platform-dependent workarounds). So I think it is a good idea to handle this in Turbo Vision.

I would like to point out a few things about your solution:

Below is a possible way of handling this from within Turbo Vision. This has to be added right after the call to setlocale in Win32ConsoleStrategy::initConsole (source/platform/win32con.cpp). Let me know if it works for you.

    if (!supportsVT)
    {
        // Disable bitmap font in legacy console because multibyte characters
        // are not displayed correctly.
        CONSOLE_FONT_INFOEX fontInfo {};
        fontInfo.cbSize = sizeof(fontInfo);
        auto isBitmap = [](UINT family)
        {
            // https://docs.microsoft.com/en-us/windows/console/console-font-infoex
            // "FontFamily: see the description of the tmPitchAndFamily member
            //  of the TEXTMETRIC structure."
            // https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-textmetricw
            // "A monospace bitmap font has all of these low-order bits clear".
            return !(family & (TMPF_FIXED_PITCH | TMPF_VECTOR | TMPF_TRUETYPE | TMPF_DEVICE));
        };
        if ( GetCurrentConsoleFontEx(StdioCtl::out(), FALSE, &fontInfo)
             && isBitmap(fontInfo.FontFamily) )
        {
            // Compute the new font height based on the bitmap font size.
            auto &oldSize = fontInfo.dwFontSize;
            short fontY = 2*min(oldSize.X, oldSize.Y);
            for (auto *name : {L"Consolas", L"Lucida Console"})
            {
                fontInfo.nFont = 0;
                fontInfo.FontFamily = FF_DONTCARE;
                fontInfo.FontWeight = FW_NORMAL;
                fontInfo.dwFontSize = {0, fontY}; // Width estimated automatically, it seems.
                wcscpy(fontInfo.FaceName, name);
                // SetCurrentConsoleFontEx succeeds even if the font is not available.
                // We need to check whether the font has actually been set.
                SetCurrentConsoleFontEx(StdioCtl::out(), FALSE, &fontInfo);
                GetCurrentConsoleFontEx(StdioCtl::out(), FALSE, &fontInfo);
                if (wcscmp(fontInfo.FaceName, name) == 0)
                    break;
            }
        }
    }
electroly commented 3 years ago

Looks great; I like your fix. I tested on both Windows 7 and Windows 10 and everything works great.

Good catch on the console handle and the raster fonts in the modern console.

I agree your way of handling the font selection is better than bringing in GDI. I initially wanted to fallback to any available monospace font if neither Consolas nor Lucida Console were available, but after determining that both fonts have shipped with Windows since Vista, I took it out. We may not need the Lucida Console fallback either, since Consolas will be there. This fallback would only be necessary on Windows XP, which ships Lucida Console but not Consolas. However, I believe tvision does not support XP. Maybe we should take out the fallback and only use Consolas to simplify the code.

Correct about the high-DPI; I'm using 175% scaling in Display Settings on a 4K monitor. One thing I noticed in my testing is that on Windows 10, the legacy console doesn't seem to apply the system scaling, but the modern console does. I initially used a size of 28 which was needed to make the legacy console readable on my screen, but then when I tried the same code on the modern console, the text was gigantic. Same issue in the other direction for the legacy console on a low-DPI test system; I had to back it down to 24 to fit on the screen at all with Windows 7's minimum resolution and default scaling. Basing the TrueType font size on the bitmap size instead of hardcoding is a clever solution that seems good enough and preserves the user's choice.

magiblot commented 3 years ago

We may not need the Lucida Console fallback either, since Consolas will be there. This fallback would only be necessary on Windows XP, which ships Lucida Console but not Consolas. However, I believe tvision does not support XP.

I have a Windows Vista VM image for testing purposes where only Lucida Console and the raster font are available, I don't know why. So there is no problem in keeping the Lucida Console fallback.

Regarding Windows XP, I was not sure whether it would still work. It builds fine using the XP toolset, but 1) UTF-8 support for RTL file-system operations is not available and 2) it does not actually run on XP due to dynamic linking errors (not caused by this change). So no, XP is not supported.

electroly commented 3 years ago

Sounds good to me. I did not actually test with Vista to see if Consolas is there; I only looked at the claims made by the font documentation. Better to keep the fallback.