1
0
Fork 0

(svn r25982) [1.3] -Backport from trunk:

- Fix: Textbuf caret rendering for complex scripts (e.g. Tamil) (r25696, r25694, r25652, r25651, r25092, r25091)
- Fix: Vehicle::MarkDirty must be called for the front engine [FS#5700] (r25695)
- Fix: [Win32] Several issues regarding conversion of characters (r25677, r25676, r25675, r25674, r25673)
- Fix: [Win32] Handle Unicode characters from outside the BMP correctly (r25672, r25670, r25669, r25668)
release/1.3
rubidium 2013-11-13 21:35:44 +00:00
parent 53fffb3bab
commit 68423b35cf
27 changed files with 208 additions and 206 deletions

View File

@ -249,7 +249,7 @@ public:
}
}
virtual EventState OnKeyPress(uint16 key, uint16 keycode)
virtual EventState OnKeyPress(WChar key, uint16 keycode)
{
const uint8 i = keycode - '1';
if (i < 9 && i < this->bridges->Length()) {

View File

@ -236,7 +236,7 @@ struct IConsoleWindow : Window
if (_iconsole_cmdline.HandleCaret()) this->SetDirty();
}
virtual EventState OnKeyPress(uint16 key, uint16 keycode)
virtual EventState OnKeyPress(WChar key, uint16 keycode)
{
if (_focused_window != this) return ES_NOT_HANDLED;

View File

@ -131,13 +131,14 @@ static void debug_print(const char *dbg, const char *buf)
fflush(f);
#endif
} else {
char buffer[512];
seprintf(buffer, lastof(buffer), "%sdbg: [%s] %s\n", GetLogPrefix(), dbg, buf);
#if defined(WINCE)
/* We need to do OTTD2FS twice, but as it uses a static buffer, we need to store one temporary */
TCHAR tbuf[512];
_sntprintf(tbuf, sizeof(tbuf), _T("%s"), OTTD2FS(dbg));
NKDbgPrintfW(_T("dbg: [%s] %s\n"), tbuf, OTTD2FS(buf));
NKDbgPrintfW(OTTD2FS(buffer));
#elif defined(WIN32) || defined(WIN64)
_fputts(OTTD2FS(buffer, true), stderr);
#else
fprintf(stderr, "%sdbg: [%s] %s\n", GetLogPrefix(), dbg, buf);
fputs(buffer, stderr);
#endif
#ifdef ENABLE_NETWORK
NetworkAdminConsole(dbg, buf);

View File

@ -300,7 +300,7 @@ public:
if (_window_system_initialized) ShowFirstError();
}
virtual EventState OnKeyPress(uint16 key, uint16 keycode)
virtual EventState OnKeyPress(WChar key, uint16 keycode)
{
if (keycode != WKC_SPACE) return ES_NOT_HANDLED;
delete this;

View File

@ -615,7 +615,7 @@ public:
}
}
virtual EventState OnKeyPress(uint16 key, uint16 keycode)
virtual EventState OnKeyPress(WChar key, uint16 keycode)
{
if (keycode == WKC_ESC) {
delete this;

View File

@ -42,26 +42,19 @@ extern FT_Library _library;
* filename into something that isn't UTF-8 but represents the Unicode file
* name. This is the short DOS 8.3 format. This does not contain any
* characters that fopen doesn't support.
* @param long_path the path in UTF-8.
* @param long_path the path in system encoding.
* @return the short path in ANSI (ASCII).
*/
char *GetShortPath(const char *long_path)
const char *GetShortPath(const TCHAR *long_path)
{
static char short_path[MAX_PATH];
#ifdef UNICODE
/* The non-unicode GetShortPath doesn't support UTF-8...,
* so convert the path to wide chars, then get the short
* path and convert it back again. */
wchar_t long_path_w[MAX_PATH];
MultiByteToWideChar(CP_UTF8, 0, long_path, -1, long_path_w, MAX_PATH);
wchar_t short_path_w[MAX_PATH];
GetShortPathNameW(long_path_w, short_path_w, MAX_PATH);
WideCharToMultiByte(CP_ACP, 0, short_path_w, -1, short_path, MAX_PATH, NULL, NULL);
WCHAR short_path_w[MAX_PATH];
GetShortPathName(long_path, short_path_w, lengthof(short_path_w));
WideCharToMultiByte(CP_ACP, 0, short_path_w, -1, short_path, lengthof(short_path), NULL, NULL);
#else
/* Technically not needed, but do it for consistency. */
GetShortPathNameA(long_path, short_path, MAX_PATH);
GetShortPathName(long_path, short_path, lengthof(short_path));
#endif
return short_path;
}
@ -82,9 +75,10 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
HKEY hKey;
LONG ret;
TCHAR vbuffer[MAX_PATH], dbuffer[256];
TCHAR *font_namep;
char *font_path;
TCHAR *pathbuf;
const char *font_path;
uint index;
size_t path_len;
/* On windows NT (2000, NT3.5, XP, etc.) the fonts are stored in the
* "Windows NT" key, on Windows 9x in the Windows key. To save us having
@ -97,15 +91,8 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
return err;
}
/* For Unicode we need some conversion between widechar and
* normal char to match the data returned by RegEnumValue,
* otherwise just use parameter */
#if defined(UNICODE)
font_namep = MallocT<TCHAR>(MAX_PATH);
MB_TO_WIDE_BUFFER(font_name, font_namep, MAX_PATH * sizeof(TCHAR));
#else
font_namep = const_cast<char *>(font_name); // only cast because in unicode pointer is not const
#endif
/* Convert font name to file system encoding. */
TCHAR *font_namep = _tcsdup(OTTD2FS(font_name));
for (index = 0;; index++) {
TCHAR *s;
@ -142,23 +129,13 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
/* Some fonts are contained in .ttc files, TrueType Collection fonts. These
* contain multiple fonts inside this single file. GetFontData however
* returns the whole file, so we need to check each font inside to get the
* proper font.
* Also note that FreeType does not support UNICODE filenames! */
#if defined(UNICODE)
/* We need a cast here back from wide because FreeType doesn't support
* widechar filenames. Just use the buffer we allocated before for the
* font_name search */
font_path = (char*)font_namep;
WIDE_TO_MB_BUFFER(vbuffer, font_path, MAX_PATH * sizeof(TCHAR));
#else
font_path = vbuffer;
#endif
* proper font. */
path_len = _tcslen(vbuffer) + _tcslen(dbuffer) + 2; // '\' and terminating nul.
pathbuf = AllocaM(TCHAR, path_len);
_sntprintf(pathbuf, path_len, _T("%s\\%s"), vbuffer, dbuffer);
ttd_strlcat(font_path, "\\", MAX_PATH * sizeof(TCHAR));
ttd_strlcat(font_path, WIDE_TO_MB(dbuffer), MAX_PATH * sizeof(TCHAR));
/* Convert the path into something that FreeType understands */
font_path = GetShortPath(font_path);
/* Convert the path into something that FreeType understands. */
font_path = GetShortPath(pathbuf);
index = 0;
do {
@ -175,9 +152,7 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
folder_error:
registry_no_font_found:
#if defined(UNICODE)
free(font_namep);
#endif
RegCloseKey(hKey);
return err;
}
@ -338,11 +313,7 @@ static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *logfont, const NEWTEXT
}
char font_name[MAX_PATH];
#if defined(UNICODE)
WIDE_TO_MB_BUFFER((const TCHAR*)logfont->elfFullName, font_name, lengthof(font_name));
#else
strecpy(font_name, (const TCHAR*)logfont->elfFullName, lastof(font_name));
#endif
convert_from_fs((const TCHAR *)logfont->elfFullName, font_name, lengthof(font_name));
/* Add english name after font name */
const char *english_name = GetEnglishFontName(logfont);

View File

@ -157,6 +157,7 @@ ParagraphLayout::VisualRun::VisualRun(Font *font, const WChar *chars, int char_c
font(font), glyph_count(char_count)
{
this->glyphs = MallocT<GlyphID>(this->glyph_count);
this->glyph_to_char = MallocT<int>(this->glyph_count);
/* Positions contains the location of the begin of each of the glyphs, and the end of the last one. */
this->positions = MallocT<float>(this->glyph_count * 2 + 2);
@ -167,6 +168,7 @@ ParagraphLayout::VisualRun::VisualRun(Font *font, const WChar *chars, int char_c
this->glyphs[i] = font->fc->MapCharToGlyph(chars[i]);
this->positions[2 * i + 2] = this->positions[2 * i] + font->fc->GetGlyphWidth(this->glyphs[i]);
this->positions[2 * i + 3] = 0;
this->glyph_to_char[i] = i;
}
}
@ -174,6 +176,7 @@ ParagraphLayout::VisualRun::VisualRun(Font *font, const WChar *chars, int char_c
ParagraphLayout::VisualRun::~VisualRun()
{
free(this->positions);
free(this->glyph_to_char);
free(this->glyphs);
}
@ -213,6 +216,15 @@ float *ParagraphLayout::VisualRun::getPositions() const
return this->positions;
}
/**
* Get the glyph-to-character map for this visual run.
* @return The glyph-to-character map.
*/
const int *ParagraphLayout::VisualRun::getGlyphToCharMap() const
{
return this->glyph_to_char;
}
/**
* Get the height of this font.
* @return The height of the font.
@ -554,7 +566,7 @@ Point Layouter::GetCharPosition(const char *ch) const
for (int i = 0; i < run->getGlyphCount(); i++) {
/* Matching glyph? Return position. */
if ((size_t)run->getGlyphToCharMap()[i] == index) {
Point p = { run->getPositions()[i * 2], run->getPositions()[i * 2 + 1] };
Point p = { (int)run->getPositions()[i * 2], (int)run->getPositions()[i * 2 + 1] };
return p;
}
}

View File

@ -125,6 +125,7 @@ public:
Font *font; ///< The font used to layout these.
GlyphID *glyphs; ///< The glyphs we're drawing.
float *positions; ///< The positions of the glyphs.
int *glyph_to_char; ///< The char index of the glyphs.
int glyph_count; ///< The number of glyphs.
public:
@ -135,6 +136,7 @@ public:
const GlyphID *getGlyphs() const;
float *getPositions() const;
int getLeading() const;
const int *getGlyphToCharMap() const;
};
/** A single line worth of VisualRuns. */

View File

@ -63,7 +63,7 @@ struct EndGameHighScoreBaseWindow : Window {
delete this;
}
virtual EventState OnKeyPress(uint16 key, uint16 keycode)
virtual EventState OnKeyPress(WChar key, uint16 keycode)
{
/* All keys are 'handled' by this window but we want to make
* sure that 'quit' still works correctly. Not handling the

View File

@ -324,7 +324,7 @@ GlobalHotkeyHandler *_global_hotkey_handlers_editor[] = {
};
void HandleGlobalHotkeys(uint16 key, uint16 keycode)
void HandleGlobalHotkeys(WChar key, uint16 keycode)
{
if (_game_mode == GM_NORMAL) {
for (uint i = 0; i < lengthof(_global_hotkey_handlers); i++) {

View File

@ -14,6 +14,7 @@
#include "core/smallvec_type.hpp"
#include "gfx_type.h"
#include "string_type.h"
/**
* All data for a single hotkey. The name (for saving/loading a configfile),
@ -130,6 +131,6 @@ void LoadHotkeysFromConfig();
void SaveHotkeysToConfig();
void HandleGlobalHotkeys(uint16 key, uint16 keycode);
void HandleGlobalHotkeys(WChar key, uint16 keycode);
#endif /* HOTKEYS_H */

View File

@ -1016,7 +1016,7 @@ struct QueryWindow : public Window {
}
}
virtual EventState OnKeyPress(uint16 key, uint16 keycode)
virtual EventState OnKeyPress(WChar key, uint16 keycode)
{
/* ESC closes the window, Enter confirms the action */
switch (keycode) {

View File

@ -491,7 +491,7 @@ struct NetworkChatWindow : public Window {
}
}
virtual EventState OnKeyPress(uint16 key, uint16 keycode)
virtual EventState OnKeyPress(WChar key, uint16 keycode)
{
EventState state = ES_NOT_HANDLED;
if (keycode == WKC_TAB) {

View File

@ -799,7 +799,7 @@ public:
}
}
virtual EventState OnKeyPress(uint16 key, uint16 keycode)
virtual EventState OnKeyPress(WChar key, uint16 keycode)
{
switch (keycode) {
case WKC_UP:

View File

@ -793,7 +793,7 @@ public:
this->SetDirty();
}
virtual EventState OnKeyPress(uint16 key, uint16 keycode)
virtual EventState OnKeyPress(WChar key, uint16 keycode)
{
EventState state = ES_NOT_HANDLED;

View File

@ -1234,7 +1234,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
this->SetWidgetDisabledState(WID_NS_PRESET_SAVE, has_missing);
}
virtual EventState OnKeyPress(uint16 key, uint16 keycode)
virtual EventState OnKeyPress(WChar key, uint16 keycode)
{
if (!this->editable) return ES_NOT_HANDLED;

View File

@ -449,7 +449,7 @@ struct NewsWindow : Window {
}
}
virtual EventState OnKeyPress(uint16 key, uint16 keycode)
virtual EventState OnKeyPress(WChar key, uint16 keycode)
{
if (keycode == WKC_SPACE) {
/* Don't continue. */

View File

@ -10,12 +10,6 @@
/** @file crashlog_win.cpp Implementation of a crashlogger for Windows */
#include "../../stdafx.h"
#if defined(_MSC_VER) && defined(_M_AMD64)
/* Redefine WinNT version to get RtlCaptureContext prototype. */
#undef _WIN32_WINNT
#undef NTDDI_VERSION
#define _WIN32_WINNT _WIN32_WINNT_WINXP
#endif /* defined(_MSC_VER) && defined(_M_AMD64) */
#include "../../crashlog.h"
#include "win32.h"
#include "../../core/alloc_func.hpp"
@ -197,7 +191,7 @@ static char *PrintModuleInfo(char *output, const char *last, HMODULE mod)
GetModuleFileName(mod, buffer, MAX_PATH);
GetFileInfo(&dfi, buffer);
output += seprintf(output, last, " %-20s handle: %p size: %d crc: %.8X date: %d-%.2d-%.2d %.2d:%.2d:%.2d\n",
WIDE_TO_MB(buffer),
FS2OTTD(buffer),
mod,
dfi.size,
dfi.crc32,
@ -621,11 +615,9 @@ static INT_PTR CALLBACK CrashDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARA
{
switch (msg) {
case WM_INITDIALOG: {
#if defined(UNICODE)
/* We need to put the crash-log in a separate buffer because the default
* buffer in MB_TO_WIDE is not large enough (512 chars) */
wchar_t crash_msgW[lengthof(CrashLogWindows::current->crashlog)];
#endif
TCHAR crash_msgW[lengthof(CrashLogWindows::current->crashlog)];
/* Convert unix -> dos newlines because the edit box only supports that properly :( */
const char *unix_nl = CrashLogWindows::current->crashlog;
char dos_nl[lengthof(CrashLogWindows::current->crashlog)];
@ -655,7 +647,7 @@ static INT_PTR CALLBACK CrashDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARA
}
SetDlgItemText(wnd, 10, text);
SetDlgItemText(wnd, 11, MB_TO_WIDE_BUFFER(dos_nl, crash_msgW, lengthof(crash_msgW)));
SetDlgItemText(wnd, 11, convert_to_fs(dos_nl, crash_msgW, lengthof(crash_msgW)));
SendDlgItemMessage(wnd, 11, WM_SETFONT, (WPARAM)GetStockObject(ANSI_FIXED_FONT), FALSE);
SetWndSize(wnd, -1);
} return TRUE;

View File

@ -78,12 +78,12 @@ bool LoadLibraryList(Function proc[], const char *dll)
void ShowOSErrorBox(const char *buf, bool system)
{
MyShowCursor(true);
MessageBox(GetActiveWindow(), MB_TO_WIDE(buf), _T("Error!"), MB_ICONSTOP);
MessageBox(GetActiveWindow(), OTTD2FS(buf), _T("Error!"), MB_ICONSTOP);
}
void OSOpenBrowser(const char *url)
{
ShellExecute(GetActiveWindow(), _T("open"), MB_TO_WIDE(url), NULL, NULL, SW_SHOWNORMAL);
ShellExecute(GetActiveWindow(), _T("open"), OTTD2FS(url), NULL, NULL, SW_SHOWNORMAL);
}
/* Code below for windows version of opendir/readdir/closedir copied and
@ -371,12 +371,10 @@ static INT_PTR CALLBACK HelpDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARAM
*q++ = *p++;
}
*q = '\0';
#if defined(UNICODE)
/* We need to put the text in a separate buffer because the default
* buffer in MB_TO_WIDE might not be large enough (512 chars) */
wchar_t help_msgW[8192];
#endif
SetDlgItemText(wnd, 11, MB_TO_WIDE_BUFFER(help_msg, help_msgW, lengthof(help_msgW)));
* buffer in OTTD2FS might not be large enough (512 chars). */
TCHAR help_msg_buf[8192];
SetDlgItemText(wnd, 11, convert_to_fs(help_msg, help_msg_buf, lengthof(help_msg_buf)));
SendDlgItemMessage(wnd, 11, WM_SETFONT, (WPARAM)GetStockObject(ANSI_FIXED_FONT), FALSE);
} return TRUE;
@ -407,12 +405,10 @@ void ShowInfo(const char *str)
_help_msg = str;
DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(101), NULL, HelpDialogFunc);
} else {
#if defined(UNICODE)
/* We need to put the text in a separate buffer because the default
* buffer in MB_TO_WIDE might not be large enough (512 chars) */
wchar_t help_msgW[8192];
#endif
MessageBox(GetActiveWindow(), MB_TO_WIDE_BUFFER(str, help_msgW, lengthof(help_msgW)), _T("OpenTTD"), MB_ICONINFORMATION | MB_OK);
* buffer in OTTD2FS might not be large enough (512 chars). */
TCHAR help_msg_buf[8192];
MessageBox(GetActiveWindow(), convert_to_fs(str, help_msg_buf, lengthof(help_msg_buf)), _T("OpenTTD"), MB_ICONINFORMATION | MB_OK);
}
MyShowCursor(old);
}
@ -426,28 +422,18 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
{
int argc;
char *argv[64]; // max 64 command line arguments
char *cmdline;
#if !defined(UNICODE)
_codepage = GetACP(); // get system codepage as some kind of a default
#endif /* UNICODE */
CrashLog::InitialiseCrashLog();
#if defined(UNICODE)
#if !defined(WINCE)
#if defined(UNICODE) && !defined(WINCE)
/* Check if a win9x user started the win32 version */
if (HasBit(GetVersion(), 31)) usererror("This version of OpenTTD doesn't run on windows 95/98/ME.\nPlease download the win9x binary and try again.");
#endif
/* For UNICODE we need to convert the commandline to char* _AND_
* save it because argv[] points into this buffer and thus needs to
* be available between subsequent calls to FS2OTTD() */
char cmdlinebuf[MAX_PATH];
#endif /* UNICODE */
cmdline = WIDE_TO_MB_BUFFER(GetCommandLine(), cmdlinebuf, lengthof(cmdlinebuf));
/* Convert the command line to UTF-8. We need a dedicated buffer
* for this because argv[] points into this buffer and this needs to
* be available between subsequent calls to FS2OTTD(). */
char *cmdline = strdup(FS2OTTD(GetCommandLine()));
#if defined(_DEBUG)
CreateConsole();
@ -463,6 +449,7 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
argc = ParseCommandLine(cmdline, argv, lengthof(argv));
ttd_main(argc, argv);
free(cmdline);
return 0;
}
@ -490,12 +477,10 @@ char *getcwd(char *buf, size_t size)
/* GetModuleFileName returns dir with file, so remove everything behind latest '\\' */
char *p = strrchr(buf, '\\');
if (p != NULL) *p = '\0';
#elif defined(UNICODE)
#else
TCHAR path[MAX_PATH];
GetCurrentDirectory(MAX_PATH - 1, path);
convert_from_fs(path, buf, size);
#else
GetCurrentDirectory(size, buf);
#endif
return buf;
}
@ -507,7 +492,7 @@ void DetermineBasePaths(const char *exe)
TCHAR path[MAX_PATH];
#ifdef WITH_PERSONAL_DIR
if (SUCCEEDED(OTTDSHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, path))) {
strecpy(tmp, WIDE_TO_MB_BUFFER(path, tmp, lengthof(tmp)), lastof(tmp));
strecpy(tmp, FS2OTTD(path), lastof(tmp));
AppendPathSeparator(tmp, MAX_PATH);
ttd_strlcat(tmp, PERSONAL_DIR, MAX_PATH);
AppendPathSeparator(tmp, MAX_PATH);
@ -517,7 +502,7 @@ void DetermineBasePaths(const char *exe)
}
if (SUCCEEDED(OTTDSHGetFolderPath(NULL, CSIDL_COMMON_DOCUMENTS, NULL, SHGFP_TYPE_CURRENT, path))) {
strecpy(tmp, WIDE_TO_MB_BUFFER(path, tmp, lengthof(tmp)), lastof(tmp));
strecpy(tmp, FS2OTTD(path), lastof(tmp));
AppendPathSeparator(tmp, MAX_PATH);
ttd_strlcat(tmp, PERSONAL_DIR, MAX_PATH);
AppendPathSeparator(tmp, MAX_PATH);
@ -540,12 +525,12 @@ void DetermineBasePaths(const char *exe)
_searchpaths[SP_BINARY_DIR] = NULL;
} else {
TCHAR exec_dir[MAX_PATH];
_tcsncpy(path, MB_TO_WIDE_BUFFER(exe, path, lengthof(path)), lengthof(path));
_tcsncpy(path, convert_to_fs(exe, path, lengthof(path)), lengthof(path));
if (!GetFullPathName(path, lengthof(exec_dir), exec_dir, NULL)) {
DEBUG(misc, 0, "GetFullPathName failed (%lu)\n", GetLastError());
_searchpaths[SP_BINARY_DIR] = NULL;
} else {
strecpy(tmp, WIDE_TO_MB_BUFFER(exec_dir, tmp, lengthof(tmp)), lastof(tmp));
strecpy(tmp, convert_from_fs(exec_dir, tmp, lengthof(tmp)), lastof(tmp));
char *s = strrchr(tmp, PATHSEPCHAR);
*(s + 1) = '\0';
_searchpaths[SP_BINARY_DIR] = strdup(tmp);
@ -567,11 +552,11 @@ bool GetClipboardContents(char *buffer, size_t buff_len)
cbuf = GetClipboardData(CF_UNICODETEXT);
ptr = (const char*)GlobalLock(cbuf);
const char *ret = convert_from_fs((const wchar_t*)ptr, buffer, buff_len);
int out_len = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)ptr, -1, buffer, (int)buff_len, NULL, NULL);
GlobalUnlock(cbuf);
CloseClipboard();
if (*ret == '\0') return false;
if (out_len == 0) return false;
#if !defined(UNICODE)
} else if (IsClipboardFormatAvailable(CF_TEXT)) {
OpenClipboard(NULL);
@ -613,26 +598,7 @@ void CSleep(int milliseconds)
const char *FS2OTTD(const TCHAR *name)
{
static char utf8_buf[512];
#if defined(UNICODE)
return convert_from_fs(name, utf8_buf, lengthof(utf8_buf));
#else
char *s = utf8_buf;
for (; *name != '\0'; name++) {
wchar_t w;
int len = MultiByteToWideChar(_codepage, 0, name, 1, &w, 1);
if (len != 1) {
DEBUG(misc, 0, "[utf8] M2W error converting '%c'. Errno %lu", *name, GetLastError());
continue;
}
if (s + Utf8CharLen(w) >= lastof(utf8_buf)) break;
s += Utf8Encode(s, w);
}
*s = '\0';
return utf8_buf;
#endif /* UNICODE */
}
/**
@ -644,34 +610,13 @@ const char *FS2OTTD(const TCHAR *name)
* The returned value's contents can only be guaranteed until the next call to
* this function. So if the value is needed for anything else, use convert_from_fs
* @param name pointer to a valid string that will be converted (UTF8)
* @param console_cp convert to the console encoding instead of the normal system encoding.
* @return pointer to the converted string; if failed string is of zero-length
* @see the current code-page comes from video\win32_v.cpp, event-notification
* WM_INPUTLANGCHANGE
*/
const TCHAR *OTTD2FS(const char *name)
const TCHAR *OTTD2FS(const char *name, bool console_cp)
{
static TCHAR system_buf[512];
#if defined(UNICODE)
return convert_to_fs(name, system_buf, lengthof(system_buf));
#else
char *s = system_buf;
for (WChar c; (c = Utf8Consume(&name)) != '\0';) {
if (s >= lastof(system_buf)) break;
char mb;
int len = WideCharToMultiByte(_codepage, 0, (wchar_t*)&c, 1, &mb, 1, NULL, NULL);
if (len != 1) {
DEBUG(misc, 0, "[utf8] W2M error converting '0x%X'. Errno %lu", c, GetLastError());
continue;
}
*s++ = mb;
}
*s = '\0';
return system_buf;
#endif /* UNICODE */
return convert_to_fs(name, system_buf, lengthof(system_buf), console_cp);
}
@ -683,14 +628,26 @@ const TCHAR *OTTD2FS(const char *name)
* @param buflen length in characters of the receiving buffer
* @return pointer to utf8_buf. If conversion fails the string is of zero-length
*/
char *convert_from_fs(const wchar_t *name, char *utf8_buf, size_t buflen)
char *convert_from_fs(const TCHAR *name, char *utf8_buf, size_t buflen)
{
int len = WideCharToMultiByte(CP_UTF8, 0, name, -1, utf8_buf, (int)buflen, NULL, NULL);
if (len == 0) {
DEBUG(misc, 0, "[utf8] W2M error converting wide-string. Errno %lu", GetLastError());
#if defined(UNICODE)
const WCHAR *wide_buf = name;
#else
/* Convert string from the local codepage to UTF-16. */
int wide_len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
if (wide_len == 0) {
utf8_buf[0] = '\0';
return utf8_buf;
}
WCHAR *wide_buf = AllocaM(WCHAR, wide_len);
MultiByteToWideChar(CP_ACP, 0, name, -1, wide_buf, wide_len);
#endif
/* Convert UTF-16 string to UTF-8. */
int len = WideCharToMultiByte(CP_UTF8, 0, wide_buf, -1, utf8_buf, (int)buflen, NULL, NULL);
if (len == 0) utf8_buf[0] = '\0';
return utf8_buf;
}
@ -702,17 +659,29 @@ char *convert_from_fs(const wchar_t *name, char *utf8_buf, size_t buflen)
* @param utf16_buf pointer to a valid wide-char buffer that will receive the
* converted string
* @param buflen length in wide characters of the receiving buffer
* @param console_cp convert to the console encoding instead of the normal system encoding.
* @return pointer to utf16_buf. If conversion fails the string is of zero-length
*/
wchar_t *convert_to_fs(const char *name, wchar_t *utf16_buf, size_t buflen)
TCHAR *convert_to_fs(const char *name, TCHAR *system_buf, size_t buflen, bool console_cp)
{
int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, utf16_buf, (int)buflen);
#if defined(UNICODE)
int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, system_buf, (int)buflen);
if (len == 0) system_buf[0] = '\0';
#else
int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0);
if (len == 0) {
DEBUG(misc, 0, "[utf8] M2W error converting '%s'. Errno %lu", name, GetLastError());
utf16_buf[0] = '\0';
system_buf[0] = '\0';
return system_buf;
}
return utf16_buf;
WCHAR *wide_buf = AllocaM(WCHAR, len);
MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_buf, len);
len = WideCharToMultiByte(console_cp ? CP_OEMCP : CP_ACP, 0, wide_buf, len, system_buf, (int)buflen, NULL, NULL);
if (len == 0) system_buf[0] = '\0';
#endif
return system_buf;
}
/**

View File

@ -18,26 +18,19 @@ bool MyShowCursor(bool show, bool toggle = false);
typedef void (*Function)(int);
bool LoadLibraryList(Function proc[], const char *dll);
char *convert_from_fs(const wchar_t *name, char *utf8_buf, size_t buflen);
wchar_t *convert_to_fs(const char *name, wchar_t *utf16_buf, size_t buflen);
char *convert_from_fs(const TCHAR *name, char *utf8_buf, size_t buflen);
TCHAR *convert_to_fs(const char *name, TCHAR *utf16_buf, size_t buflen, bool console_cp = false);
/* Function shortcuts for UTF-8 <> UNICODE conversion. When unicode is not
* defined these macros return the string passed to them, with UNICODE
* they return a pointer to the converted string. The only difference between
* XX_TO_YY and XX_TO_YY_BUFFER is that with the buffer variant you can
* specify where to put the converted string (and how long it can be). Without
* the buffer and internal buffer is used, of max 512 characters */
* they return a pointer to the converted string. These functions use an
* internal buffer of max 512 characters. */
#if defined(UNICODE)
# define MB_TO_WIDE(str) OTTD2FS(str)
# define MB_TO_WIDE_BUFFER(str, buffer, buflen) convert_to_fs(str, buffer, buflen)
# define WIDE_TO_MB(str) FS2OTTD(str)
# define WIDE_TO_MB_BUFFER(str, buffer, buflen) convert_from_fs(str, buffer, buflen)
#else
extern uint _codepage; // local code-page in the system @see win32_v.cpp:WM_INPUTLANGCHANGE
# define MB_TO_WIDE(str) (str)
# define MB_TO_WIDE_BUFFER(str, buffer, buflen) (str)
# define WIDE_TO_MB(str) (str)
# define WIDE_TO_MB_BUFFER(str, buffer, buflen) (str)
#endif
HRESULT OTTDSHGetFolderPath(HWND, int, HANDLE, DWORD, LPTSTR);

View File

@ -177,15 +177,24 @@
/* Stuff for MSVC */
#if defined(_MSC_VER)
#pragma once
/* Define a win32 target platform, to override defaults of the SDK
* We need to define NTDDI version for Vista SDK, but win2k is minimum */
#define NTDDI_VERSION NTDDI_WIN2K // Windows 2000
#define _WIN32_WINNT 0x0500 // Windows 2000
#define _WIN32_WINDOWS 0x400 // Windows 95
#if !defined(WINCE)
#define WINVER 0x0400 // Windows NT 4.0 / Windows 95
#ifdef _WIN64
/* No 64-bit Windows below XP, so we can safely assume it as the target platform. */
#define NTDDI_VERSION NTDDI_WINXP // Windows XP
#define _WIN32_WINNT 0x501 // Windows XP
#define _WIN32_WINDOWS 0x501 // Windows XP
#define WINVER 0x0501 // Windows XP
#define _WIN32_IE_ 0x0600 // 6.0 (XP+)
#else
/* Define a win32 target platform, to override defaults of the SDK
* We need to define NTDDI version for Vista SDK, but win2k is minimum */
#define NTDDI_VERSION NTDDI_WIN2K // Windows 2000
#define _WIN32_WINNT 0x0500 // Windows 2000
#define _WIN32_WINDOWS 0x400 // Windows 95
#if !defined(WINCE)
#define WINVER 0x0400 // Windows NT 4.0 / Windows 95
#endif
#define _WIN32_IE_ 0x0401 // 4.01 (win98 and NT4SP5+)
#endif
#define _WIN32_IE_ 0x0401 // 4.01 (win98 and NT4SP5+)
#define NOMINMAX // Disable min/max macros in windows.h.
#pragma warning(disable: 4244) // 'conversion' conversion from 'type1' to 'type2', possible loss of data
@ -287,7 +296,7 @@
#endif /* WINCE */
const char *FS2OTTD(const TCHAR *name);
const TCHAR *OTTD2FS(const char *name);
const TCHAR *OTTD2FS(const char *name, bool console_cp = false);
#define SQ2OTTD(name) FS2OTTD(name)
#define OTTD2SQ(name) OTTD2FS(name)
#else

View File

@ -362,7 +362,7 @@ bool Textbuf::HandleCaret()
return false;
}
HandleKeyPressResult Textbuf::HandleKeyPress(uint16 key, uint16 keycode)
HandleKeyPressResult Textbuf::HandleKeyPress(WChar key, uint16 keycode)
{
bool edited = false;

View File

@ -56,7 +56,7 @@ struct Textbuf {
bool DeleteChar(uint16 keycode);
bool MovePos(uint16 keycode);
HandleKeyPressResult HandleKeyPress(uint16 key, uint16 keycode);
HandleKeyPressResult HandleKeyPress(WChar key, uint16 keycode);
bool HandleCaret();
void UpdateSize();

View File

@ -853,6 +853,10 @@ static void RunVehicleDayProc()
}
if (HasBit(callback, 1)) v->colourmap = PAL_NONE;
/* After a vehicle trigger, the graphics and properties of the vehicle could change.
* Note: MarkDirty also invalidates the palette, which is the meaning of bit 1. So, nothing special there. */
if (callback != 0) v->First()->MarkDirty();
if (callback & ~3) ErrorUnknownCallbackResult(v->GetGRFID(), CBID_VEHICLE_32DAY_CALLBACK, callback);
}
}

View File

@ -50,9 +50,6 @@ bool _window_maximize;
uint _display_hz;
uint _fullscreen_bpp;
static Dimension _bck_resolution;
#if !defined(UNICODE)
uint _codepage;
#endif
/** Whether the drawing is/may be done in a separate thread. */
static bool _draw_threaded;
@ -439,12 +436,61 @@ static void PaintWindowThread(void *)
}
/** Forward key presses to the window system. */
static LRESULT HandleCharMsg(uint keycode, uint charcode)
static LRESULT HandleCharMsg(uint keycode, WChar charcode)
{
#if !defined(UNICODE)
wchar_t w;
int len = MultiByteToWideChar(_codepage, 0, (char*)&charcode, 1, &w, 1);
charcode = len == 1 ? w : 0;
static char prev_char = 0;
char input[2] = {(char)charcode, 0};
int input_len = 1;
if (prev_char != 0) {
/* We stored a lead byte previously, combine it with this byte. */
input[0] = prev_char;
input[1] = (char)charcode;
input_len = 2;
} else if (IsDBCSLeadByte(charcode)) {
/* We got a lead byte, store and exit. */
prev_char = charcode;
return 0;
}
prev_char = 0;
wchar_t w[2]; // Can get up to two code points as a result.
int len = MultiByteToWideChar(CP_ACP, 0, input, input_len, w, 2);
switch (len) {
case 1: // Normal unicode character.
charcode = w[0];
break;
case 2: // Got an UTF-16 surrogate pair back.
charcode = Utf16DecodeSurrogate(w[0], w[1]);
break;
default: // Some kind of error.
DEBUG(driver, 1, "Invalid DBCS character sequence encountered, dropping input");
charcode = 0;
break;
}
#else
static WChar prev_char = 0;
/* Did we get a lead surrogate? If yes, store and exit. */
if (Utf16IsLeadSurrogate(charcode)) {
if (prev_char != 0) DEBUG(driver, 1, "Got two UTF-16 lead surrogates, dropping the first one");
prev_char = charcode;
return 0;
}
/* Stored lead surrogate and incoming trail surrogate? Combine and forward to input handling. */
if (prev_char != 0) {
if (Utf16IsTrailSurrogate(charcode)) {
charcode = Utf16DecodeSurrogate(prev_char, charcode);
} else {
DEBUG(driver, 1, "Got an UTF-16 lead surrogate without a trail surrogate, dropping the lead surrogate");
}
}
prev_char = 0;
#endif /* UNICODE */
HandleKeypress(GB(charcode, 0, 16) | (keycode << 16));
@ -586,16 +632,17 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP
return 0;
}
#if !defined(WINCE) || _WIN32_WCE >= 0x400
#if !defined(UNICODE)
case WM_INPUTLANGCHANGE: {
TCHAR locale[6];
LCID lcid = GB(lParam, 0, 16);
int len = GetLocaleInfo(lcid, LOCALE_IDEFAULTANSICODEPAGE, locale, lengthof(locale));
if (len != 0) _codepage = _ttoi(locale);
return 1;
}
#endif /* UNICODE */
case WM_IME_CHAR:
if (GB(wParam, 8, 8) != 0) {
/* DBCS character, send lead byte first. */
HandleCharMsg(0, GB(wParam, 8, 8));
}
HandleCharMsg(0, GB(wParam, 0, 8));
return 0;
#endif
#endif
case WM_DEADCHAR:
console = GB(lParam, 16, 8) == 41;

View File

@ -2248,7 +2248,7 @@ static bool MaybeBringWindowToFront(Window *w)
* @return #ES_HANDLED if the key press has been handled and no other
* window should receive the event.
*/
EventState Window::HandleEditBoxKey(int wid, uint16 key, uint16 keycode)
EventState Window::HandleEditBoxKey(int wid, WChar key, uint16 keycode)
{
QueryString *query = this->GetQueryString(wid);
if (query == NULL) return ES_NOT_HANDLED;

View File

@ -19,6 +19,7 @@
#include "widget_type.h"
#include "core/smallvec_type.hpp"
#include "core/smallmap_type.hpp"
#include "string_type.h"
/** State of handling an event. */
enum EventState {
@ -465,7 +466,7 @@ public:
void UnfocusFocusedWidget();
bool SetFocusedWidget(int widget_index);
EventState HandleEditBoxKey(int wid, uint16 key, uint16 keycode);
EventState HandleEditBoxKey(int wid, WChar key, uint16 keycode);
void HandleButtonClick(byte widget);
int GetRowFromWidget(int clickpos, int widget, int padding, int line_height = -1) const;
@ -570,7 +571,7 @@ public:
* @return #ES_HANDLED if the key press has been handled and no other
* window should receive the event.
*/
virtual EventState OnKeyPress(uint16 key, uint16 keycode) { return ES_NOT_HANDLED; }
virtual EventState OnKeyPress(WChar key, uint16 keycode) { return ES_NOT_HANDLED; }
/**
* The state of the control key has changed