В виндовую консоль надо писать WriteConsoleW, который принципиально UCS2. Тут, правда, с виндовой консолью свои заморочки. Ведь вывод команды может захотеться перенаправить в файл или трубу, а в файл или трубу нельзя сделать WriteConsoleW. Значит, надо на старте понять, чем являются перенаправленные каналы Input, Output, ErrOutput, и в зависимости от этого писать в них через WriteConsoleW или через WriteFile.
Вот если через WriteFile работать с консолью, тогда да, тут возникают кодировки. Тоже тут не обходится без шаманства, но
девять лет назад уже как всё разобрали и какой современный node.js ни возьми, никакую «кодировку» из него в консоль не выдавишь. JavaScript в node.js оперирует UTF-16, и этот UTF-16 так и идёт в консоль.
Адский транслятор GNAT базируется на GCC, а в GCC для совместимости с POSIX потоки 8битные, однако там сделана прослойка, которая обнаруживает наличие консоли Windows, и при обнаружении консоли перекодирует из UTF-8 в UTF-16 и пишет с использованием WriteConsoleW. Везде в современных библиотеках времени исполнения эту дыру, чтоб запись в консоль Windows могла провалиться во WriteFile, позакрывали. Везде поставили это нехитрое шаманство. А у FPC за 9 лет, похоже, таких рабочих рук не нашлось, и он остался в каменном веке. Пишет через WriteFile. Впрочем, я сейчас посмотрел, как в Delphi Tokyo на работе, и там тоже это убожество с кодировками вместо WriteConsoleW. System.Write юникодный, но затем он перекодирует в однобайтовую системную кодировку.
В общем, кодировкам, отличным от кодировок Юникода, решительный бой. А если эти кодировки прямо в сердце, в стандартной библиотеке, то такой стандартной библиотеке решительный бой. И даже шаманства особого не потребуется. Шаманство нужно, если не понятно, перенаправлен вывод или нет. Рисовать диалоги в выводе, перенаправленном в файл или трубу — занятие бессмысленное, так что прописывать отдельно вывод в файл и консоль, и различение между ними, бессмысленно. Только консоль, только консольное WinAPI, а оно довольно простое.