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

Support older Windows versions anyway :-P #173

Open
eyalroz opened this issue Jul 11, 2022 · 32 comments
Open

Support older Windows versions anyway :-P #173

eyalroz opened this issue Jul 11, 2022 · 32 comments
Assignees
Labels
enhancement New feature or request
Milestone

Comments

@eyalroz
Copy link

eyalroz commented Jul 11, 2022

I know the README says Windows < 10 is not supported because of lack of proper ANSI support.

But - people have been writing and using Windows terminal/command-prompt apps for years before Windows 10 came around. Sure, maybe they used something broken that's not ANSI. But - would it be that unrealistic to support that as well?

@certik
Copy link
Collaborator

certik commented Jul 11, 2022

If it is maintainable, we'll accept PRs to support older Windows. One approach might be to emulate the ANSI support, so we can just keep using ANSI in the rest of the library.

@MCWertGaming
Copy link
Collaborator

Hi! I have actually tested windows compatibility with windows 8.1 and below and while it still compiles with MSVC, the constructor of the Terminal class (which is the core of the library, as it sets the terminal into "raw mode" so we can control the terminal manually) fails. The reason for the failing is that one function that we call of the Win32 API throws a runtime error on those versions of windows. I guess that they haven't implemented the functionality in the Win32 API at all.

Windows 8.1 and below use other parts of the win32 API than we do. Also i'm not sure if the "raw mode" is supported at all. I'll investigate this. Managing colors in the old CMD works by using special Win32 functions, they only support 3bit or 4bit colors though, so we would need to

  • find a way to check the windows version on runtime properly
  • on windows 8.1 and below we need to switch over to a method of entering the "raw mode" that works on older versions (if it's possible at all)
  • the color() function would need to switch over to the old way of printing colors in the CMD on those versions
  • the Window class needs to force 4bit or 3bit colors on those windows versions

So supporting windows 8 and below would mean much work and research. Currently the best would be to compile your program using MSYS2 or MinGW / Cygwin as they are using a ported version of Glibc (wich uses the linux version of the Terminal class constructor).
When you want to run the program outside of the chroot environment without packing the runtime along, you can compile using -Static when you call GCC or set the CMAKE_CXX_FLAGS cmake variable in cmake when compiling to compile glibc etc into the binary to make it stand-alone.

Compiling statically produces bigger binaries, but it makes packaging and installing the program a lot easier.

I'll add this to the roadmap to look into it later. When you would like to have this added quicker, feel free to contribute by researching ways on possible solutions! I'm currently working on the new window class, you can see the current development in the roadmap:
https://github.com/jupyter-xeus/cpp-terminal/projects/1

If you need help with the work around, feel free to ask!

@MCWertGaming MCWertGaming self-assigned this Jul 12, 2022
@MCWertGaming MCWertGaming added the enhancement New feature or request label Jul 12, 2022
@MCWertGaming MCWertGaming added this to the V1.0.0 milestone Jul 12, 2022
@MCWertGaming
Copy link
Collaborator

moved the documentation update to #174.

@flagarde
Copy link
Collaborator

flagarde commented Jul 13, 2022

Hi,

I found back this : https://gist.github.com/mlocati/21a9233ac83f7d3d7837535bc109b3b7
to check version of windows and apply color. It should solve one or two point of @MCWertGaming post

https://github.com/adoxa/ansicon seems to do what you are looking for... Maybe a merging of the two code could be done (it seems the LICENSE is quite open but i'm not lawyer so it must be cross-checked)

@MCWertGaming
Copy link
Collaborator

The gist contains pretty cool checks to be honest. We can definitely use that. The other project would need a bit fixing and refactoring as far as I saw, should be pretty simple though. We should definitely look into that. The License is a custom one, but it reads like MIT, so I guess that adding the copyright to our license would be enough to comply. Much testing is needed, maybe we can simply use another part of the Win32 API that works on all windows versions. I'll look into that after i'm finished with the window class re-working. So it might take a bit for now.

@flagarde if you want to look into this, I can help you. But the Window class is more important right now for me as it's needed for some of my projects.

@flagarde
Copy link
Collaborator

flagarde commented Jul 14, 2022

I don't know if I will have time but I could try if I can. Indeed the 'ansicon' needs to be refactored and included but it gives a hints on what could be done.

For the gist if I understood correctly, the actual code, before Win10 crashes because it doesn't recognize some new features. Addind the version check and using it to avoid the crash could be the first step

@MCWertGaming
Copy link
Collaborator

No problem, we have time. The first thing we should look into, would probably be the Terminal class. We should modify it so the runtime error that happens on windows if fixed, or (if possible) make a small re-write of it using a method that works across windows versions. Does ansicon include code to put the terminal into "raw mode"? That would be the most important thing for now as it's the core of the library that allows us to have full control over the terminal and things like input.

When we updated the Terminal class, we can move to updating the color function and the Window class (which is hopefully merged until then).

@MCWertGaming
Copy link
Collaborator

This seems to be suitable for converting the 8bit colors (that are coming with the next Window class update) into windows XP / later versions of windows. I have created a "Auto color" function that does auto fallback to 8bit colors when 24bit are not supported (because MacOS terminal and the VGA console on linux are not supporting them, but 8bit it pretty widely supported).
https://github.com/adoxa/ansicon/blob/master/palette.h

So I could Imagine that we just create a function that determines the windows version, and if it's windows 8.1 to XP / 2000, we are just returning the string of the legacy windows terminal instead of the ANSI version.

@MCWertGaming
Copy link
Collaborator

I don't see any code for changing the terminal mode though in ansicon, I think it's just for terminal colors.

I have looked through the Microsoft docs and they note:

Checking whether SetConsoleMode returns 0 and GetLastError returns ERROR_INVALID_PARAMETER is the current mechanism to determine when running on a down-level system. An application receiving ERROR_INVALID_PARAMETER with one of the newer console mode flags in the bit field should gracefully degrade behavior and try again.

So we would have to change https://github.com/jupyter-xeus/cpp-terminal/blob/master/cpp-terminal/private/platform.cpp#L166 to check the return value, it it's 0 and the error is invalid parameter as described here:
https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences
When the error happens, we would have to try again with less flags enabled so we would have to find out which flag is causing the error.

@flagarde
Copy link
Collaborator

Yes is what I was thinking. Determine the windows version then depending on this turn the raw mode with ANSI handling or not. If windows is too old we need to parse the input to see if there is ANSI and fallback to the legacy windows terminal function for each

@flagarde
Copy link
Collaborator

flagarde commented Jul 14, 2022

Seems ansicon has to do a lot of hacks we don't need to do as we don't need to injects a DLL into a process, hooking its functions. . I think the easiest solution could be to let windows 10 deal himself with ANSI and if windows is older parse the ANSI by ourselft and trigger the good Windows functions base on the ANSI value. Mainly take the InterpretEscSeq() in https://github.com/adoxa/ansicon/blob/master/ANSI.c and plug it on input.cpp

@MCWertGaming
Copy link
Collaborator

Well for the raw mode, we just have to find out which console modes are supported on the oldest windows version we want to support and then, when setting them fails, just try again with less flags turned on. The ansi fallback would be something to look into after that. parsing then ansi codes is pretty complicated, also microsoft writes that the virtual terminal modes (which we are using) provides a unified interface for all windows versions, so I assume that they have added the ansi patches for the cmd and powershell 2 already for later versions. If so we can simply skip the changes to the ansi functions.

@MCWertGaming
Copy link
Collaborator

MCWertGaming commented Jul 14, 2022

I don't think that we need the InpretEscSeq function, it looks like a work around. Have you tested if the color example works on windows 8 / 7 / XP? @flagarde

We should test that first.

@MCWertGaming
Copy link
Collaborator

MCWertGaming commented Jul 14, 2022

Also: input.hpp only contains functions for handling input from the console. base.hpp includes everything ansi related.

@flagarde
Copy link
Collaborator

flagarde commented Jul 15, 2022

Well correct me if I'm wrong. For now we let windows deals with the ANSI so if we send :
\033[1mHello windows eat the \033[1m interpret it and do all for us. If windows is too old then windows don't know how to interpret the ANSI so will send it directly. So at least cpp-terminal should eat this and do nothing printing Hello. base.hpp is very usefull but what would happen if the text is received by other software or given by user ?

For example I have some program running on computer A sending \033[1mHello to B some text with ANSI. How to deal with this in case windows is too old. From my understanding it will print \033[1mHello. At least it should supress \033[1m, or even better use the old windows function to switch color etc.

@MCWertGaming
Copy link
Collaborator

In early days of windows, the cmd.exe wasn't supporting ANSI and microsoft provided an API to set colors. After they added ANSI support to both powershell and cmd we got the new API by microsoft that we are currently using. CMD is doing conversions to allow full ANSI support, because it's not supporting more than 4bit colors.

But we should check if the ANSI support was back-ported by microsoft already. Testing it would mean to simply run the colors example on a windows 7/8/8.1 installation and to look if the colors are showing.

Currently only the terminal preparation on the terminal class doesn't work for older windows versions.

ANSI might be an additional problem. We should investigate them separately.

@flagarde
Copy link
Collaborator

flagarde commented Jul 15, 2022

I have to check on old windows but I think is not back ported. I was hoping the fmt library which deals with color text too had color support on all windows versions but they said the console need to accept Ansi.

Parsing ansi esc seems not too difficult and some project seem to have done it :

https://github.com/mattn/ansicolor-w32.c

I put it here if it's needed in the future

@MCWertGaming
Copy link
Collaborator

Yeah, we should stick to the docs by microsoft though. They are stating that setting the virtual terminal mode provides well compatibility. So we might get it done that way. If not we should look into alternative approaches. creating a custom print function might not be a nice solution though because some people might want to do additional processing, the Window class also does parsing and redering of the UTF8 characters as C++ isn't supporting it out of the box.

@flagarde
Copy link
Collaborator

Yes sure the print solution hack is not a good solution but the ANSI parsing done inside could be a hint how to parse ANSI in case it should be given by the library

@flagarde
Copy link
Collaborator

I have tried to compile on windows 8.1 with latest MSVC and as you mentioned some flags are problematic. Using some code to test the version from https://gist.github.com/mlocati/21a9233ac83f7d3d7837535bc109b3b7 I has able to disable the flags only if they are not available. of course then colors is not working, all ANSI escape sequences are printed verbatim

@MCWertGaming
Copy link
Collaborator

Really nice! So it fails because the older terminal don't support ANSI? then this will be a really quick fix. do you mind making a PR? @flagarde

The code that has to changed is here https://github.com/jupyter-xeus/cpp-terminal/blob/master/cpp-terminal/private/platform.cpp#L164
It's probably nice to create a function that checks if colors are support and based on that the BaseTerminal class will set the virtual_terminal_processing flag or skip that.

The BaseTerminal class must be refactored anyway. But I currently don't find enough time for cpp-terminal and am still working on the Window class update.

Funfact: I participated in a game jam and created chess using cpp-terminal. It was fun, but there is a lot to improve ^^ will look into doing specific fixes soon.

@MCWertGaming
Copy link
Collaborator

MCWertGaming commented Aug 19, 2022

Things TODO:

  • create a function for checking the terminal support for colors
  • Fix the terminal processing flag being set on windows terminals without support for it
  • create a function that checks if ANSI is possible
  • add automatic ANSI conversion to Term::auto_color()
    • auto_color() is coming with the Window class PR I'm preparing currently
    • maybe it's possible to add it directly to the color() function, but it would mean inconsistency since the 8bit and 24bit colors aren't working then

@flagarde
Copy link
Collaborator

flagarde commented Aug 19, 2022

Hi, yes I can do a PR..
If I understand correctly, on windows, if the terminal support ANSI escape code it support color...

For color stufs it should be easy to substitute the Escape code to the windows color changing function if the terminal doen't support ANSI for the rest of the escpape sequence it will be more difficult...

This means we need to parse the user input for ansi code if windows don't support it and do the stufs by ourself

@MCWertGaming
Copy link
Collaborator

We should fix the runtime error first and then when we are sure that the fix won't break anything we can move to the colors.

How would you print colors on windows versions without ANSI support? Since it's just 16 colors (4bit) we would either have to fix the Term::color() function, or create a new one and simply include it to the auto_color() function that comes with my net PR.

@flagarde
Copy link
Collaborator

flagarde commented Aug 20, 2022

Ok I will do the PR for the runtime and we can have cross-check

For the color i was thinking to fix the 16 colors first and disable the ANSII for the others at first... It will be enought for many application I think

Then I don't know what will do your auto_color but I think we could find the closest color from the 16 colors we have for a given ANSII and switch to this one.. not perfect but we have to live with the 16colors windows gives us before win10

@MCWertGaming
Copy link
Collaborator

The auto color function ban be found here master...MCWertGaming:cpp-terminal:window_class#diff-153dd787a62f23156ebd61fd1774416f2367288fe1b81068f485cc1dbf4ec463R49.

I have created functions for various conversions, mainly for the windows class, like I discussed with @certik a while ago.

I have looked into setting colors on CMD and it looks really bad to be honest. We need to make a few more changes, basically everything that is done using ANSI must be fixed, but I'm not sure if we can implement that for the color, color_24bit and color_8bit functions. Also the move_cursor function must be fixed, and a few others probably as well.

@flagarde
Copy link
Collaborator

Yes exactly we have to do everything by ourself using ugly old Windows stufs.

@flagarde flagarde mentioned this issue Aug 20, 2022
2 tasks
@flagarde
Copy link
Collaborator

I have made a PR #178 it should fix point 2 and 3

@MCWertGaming
Copy link
Collaborator

Really awesome. Thank you really much @flagarde. We have to make out how the old windows32 api works and if the same functionality is provided than with the virtual console mode (which we are using right now).

@MCWertGaming
Copy link
Collaborator

Hey, does it make sense to implement a lot of code for windows back-wards compatibility when people can just install ansicon and everything will work without any code changes?

@MCWertGaming
Copy link
Collaborator

We would just look into official support and docs on ansicon then. While I honestly hope that there aren't many cpp-terminal users with windows 8.1 or lower systems since they are out of official microsoft support for some time (while Windows 10 is leaving it as well soon).

@MCWertGaming
Copy link
Collaborator

Since #178 is merged now (which means that we are not facing a runtime error anymore), we need to look into ways on emulating ansi. I see two options here (but am open to other ideas as well!):

So which direction should we look into? @eyalroz @certik @flagarde

@flagarde flagarde moved this to V1.0.0 in CPP-Terminal Sep 16, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Status: V1.0.0
Development

No branches or pull requests

4 participants