Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
electroly opened this issue Mar 10, 2021 · 4 comments
Closed

Comments

@electroly
Copy link
Contributor

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
Copy link
Owner

magiblot commented Mar 10, 2021

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:

  • Raster fonts alone do not cause this issue; the problem arises when combining the legacy console with raster fonts. So on Windows 10, where the legacy console is optional, you can have a raster font enabled and multibyte characters being displayed correctly.
  • CONOUT$ is the most portable way to access the output buffer in Turbo Vision. Turbo Vision will access the console even if stdio is being redirected (https://github.com/magiblot/tvision/blob/b31528265bde6d4aa818bdef9afefbff3f84b830/source/platform/stdioctl.cpp, line 79), but in that case GetStdHandle(STD_OUTPUT_HANDLE) may not return a console handle. Of course, it's best if the client application needs not know about this.
  • From the pictures you've shared in other issues I deduce you are using High DPI settings (or at least you use larger fonts than me). Thus the default font height of 24 may work well for you but does not look good in my screen.
  • Personally, I'm not very enthusiastic about dealing with GDI directly. I prefer to set the font blindly and then check if it was actually set.

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
Copy link
Contributor Author

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
Copy link
Owner

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
Copy link
Contributor Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants