Don't reinvent the wheel. If you find a library that does what you want to do, use it. You're just wasting effort otherwise.
Oh? Now tell me the limitations of the implementation that your magical library has. Oh right... you don't even know how do to it yourself in the first place, let alone the problems you'll end up with in the future should you need to change libraries.
I've used ncurses and pdcurses quite a few times in the past. Don't jump so quickly to conclusions.
I am encouraging the OP to learn how to think, how to process a problem, how to read documentation (which is very easy).
Besides, there are a million odd "Rogue remakes".... why reinvent the wheel and make yet another rogue remake? It's wasted effort, right?
Diving into direct interaction with the OS is less "thinking" and more "tedious unnecessary work." By your logic it's best to write everything in assembly because it makes you "think" more. There's enough to think about when writing a program in the first place; don't make it any harder on yourself.
ncurses & pdcurses are already pretty low-level -- seriously, this is 30-year old technology. There's no reason to go any deeper.
Besides, doing what you suggest would involve interacting with the terminal/OS directly at a very low level,
Uhh... making threads is "low level" now? Directly calling win32_threads or p_threads is hardly "low level" programming. This is how people program.
Again, I think you underestimate how low-level ncurses & pdcurses are. I suggest you at least look up what they even are before you continue this discussion.
making your program unportable and probably requiring special knowledge that I doubt the OP has.
"Portable code" is often misused in the same manner you just misused it.
To show you how badly you misused code portability, I'll challenge you to tell me that win32 software is not platform independent. WINE brings many windows libraries over to *NIX systems. They're imperfect libraries, but still libraries none the less.
There is no guarantee that the system you're targeting supports threads, for instance. std::thread is just an abstraction that calls the system level threading service. The use of abstractions, rather than their implementation, is what portable code envelopes. Even if it is as simple as a macro that changes to win_threads instead of p_threads.
The cost of abstraction is the same cost that WINE pays for attempting to translate direct x routines into opengl equivalents. Performance. DirectX is used very differently when compared to opengl, an engine designed around one or the other depends on their individual ways of doing things. You could do further abstraction and make it easy to change between the two of them via header files... but as always, that way of doing things has a performance hit. Since the abstraction gets compiled in you can get some benefits over wrapping around the calls.
First of all, using WINE is damaging to performance and can sometimes be buggy. Best not to rely on it.
Second of all, by "portable" I mean being able to port to another machine without changing much (or any) of the code.
For example, if you wrote a program with ncurses on Linux you can port it to Windows by simply changing the header include and relinking with pdcurses. Nothing else has to change. ncurses and pdcurses *are* the abstractions you describe -- they envelop the differing system calls and replace them with a single, common set of functions.
If you're using the OS utilities directly, you have to either use the slow, buggy WINE or have to replace every single instance of a system call to the old OS with the equivalent in the new OS. (Or if the equivalent doesn't exist, you have to write completely new code.) Basically, you yourself are doing the abstraction which existing libraries already provide.