«Гопник-2»: UTF-8
Продолжаю писать про портирование «Гопника-2» под «Виндоуз», ибо там ещё есть о чём рассказать.
Я уже очень давно не работаю под этой операционной системой, поэтому некоторые обычные, возможно, для многих вещи для меня являются открытием. Когда я начинал процесс портирования игры под эту платформу, я был уверен, что столкнусь в трудностями совершенно в других частях кода. Одной из неожиданностей была плохая работа «Виндоуз» с кодировкой ЮТФ-8.
Если вывод в консоль удалось победить сравнительно легко, то со вводом возникли проблемы — вызов SetConsoleCP(CP_UTF8), который должен был помочь, не помог. В интернете пишут, что он, по всей видимости, не реализован — просто не делает ничего.
Если с латинскими буквами проблем не возникает, они кодируются одним байтом, это ничем не отличается от того как программы до этого работали десятилетиями, а вот с русскими буквами беда — для них требуется два байта и в таком виде Виндоуз их не понимает.
Рекомендуемый специалистами способ — переключить консоль в режим ввода кодировки ЮТФ-16, а потом перекодировать полученную строку в нужную кодировку. «Виндозу» ЮТФ-16 родная, поэтому проблем вообще никаких не возникает.
#ifdef __MINGW32__
int wlen = 100;
int save = _setmode(_fileno(stdin), _O_U16TEXT);
wchar_t *wstr = (wchar_t *) malloc(wlen * sizeof(wchar_t));
fgetws(wstr, wlen, stdin);
int len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, 0, 0, 0, 0);
user_name = (char *) malloc(len);
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, user_name, len, 0, 0);
_setmode(_fileno(stdin), save);
free(wstr);
#endif
Мне, к счастью, ввод русских букв нужен только в одном месте — там где игрок вводит своё имя. Я убрал используемую там функцию fgets под условную компиляцию и вставил кусок, который выше. С таким исправлением всё заработало, как ожидается.