2
0
Эх сурвалжийг харах

UTF-8 support for windows entry

Cloud Wu 6 жил өмнө
parent
commit
65aa58aab1

+ 76 - 45
examples/common/entry/entry_windows.cpp

@@ -18,6 +18,7 @@
 
 #include <tinystl/allocator.h>
 #include <tinystl/string.h>
+#include <tinystl/vector.h>
 
 #include <windows.h>
 #include <windowsx.h>
@@ -33,6 +34,16 @@
 
 namespace entry
 {
+	typedef tinystl::vector<WCHAR> WSTRING;
+
+	inline WSTRING UTF8ToUTF16(const char *utf8_str)
+	{
+		int len = MultiByteToWideChar(CP_UTF8, 0, utf8_str, -1, NULL, 0);
+		WSTRING utf16(len);
+		MultiByteToWideChar(CP_UTF8, 0, utf8_str, -1, utf16.data(), len);
+		return utf16;
+	}
+
 	///
 	inline void winSetHwnd(::HWND _window)
 	{
@@ -359,6 +370,7 @@ namespace entry
 			, m_init(false)
 			, m_exit(false)
 		{
+			m_surrogate = 0;
 			bx::memSet(s_translateKey, 0, sizeof(s_translateKey) );
 			s_translateKey[VK_ESCAPE]     = Key::Esc;
 			s_translateKey[VK_RETURN]     = Key::Return;
@@ -450,29 +462,29 @@ namespace entry
 
 		int32_t run(int _argc, const char* const* _argv)
 		{
-			SetDllDirectoryA(".");
+			SetDllDirectoryW(L".");
 
 			s_xinput.init();
 
-			HINSTANCE instance = (HINSTANCE)GetModuleHandle(NULL);
+			HINSTANCE instance = (HINSTANCE)GetModuleHandleW(NULL);
 
-			WNDCLASSEXA wnd;
+			WNDCLASSEXW wnd;
 			bx::memSet(&wnd, 0, sizeof(wnd) );
 			wnd.cbSize = sizeof(wnd);
 			wnd.style = CS_HREDRAW | CS_VREDRAW;
 			wnd.lpfnWndProc = wndProc;
 			wnd.hInstance = instance;
-			wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION);
-			wnd.hCursor = LoadCursor(NULL, IDC_ARROW);
-			wnd.lpszClassName = "bgfx";
-			wnd.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
-			RegisterClassExA(&wnd);
+			wnd.hIcon = LoadIconW(NULL, (LPWSTR)IDI_APPLICATION);
+			wnd.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
+			wnd.lpszClassName = L"bgfx";
+			wnd.hIconSm = LoadIconW(NULL, (LPWSTR)IDI_APPLICATION);
+			RegisterClassExW(&wnd);
 
 			m_windowAlloc.alloc();
-			m_hwnd[0] = CreateWindowExA(
+			m_hwnd[0] = CreateWindowExW(
 				  WS_EX_ACCEPTFILES
-				, "bgfx"
-				, "BGFX"
+				, L"bgfx"
+				, L"BGFX"
 				, WS_OVERLAPPEDWINDOW|WS_VISIBLE
 				, 0
 				, 0
@@ -521,10 +533,10 @@ namespace entry
 				s_xinput.update(m_eventQueue);
 				WaitForInputIdle(GetCurrentProcess(), 16);
 
-				while (0 != PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE) )
+				while (0 != PeekMessageW(&msg, NULL, 0U, 0U, PM_REMOVE) )
 				{
 					TranslateMessage(&msg);
-					DispatchMessage(&msg);
+					DispatchMessageW(&msg);
 				}
 			}
 
@@ -548,8 +560,8 @@ namespace entry
 				case WM_USER_WINDOW_CREATE:
 					{
 						Msg* msg = (Msg*)_lparam;
-						HWND hwnd = CreateWindowA("bgfx"
-							, msg->m_title.c_str()
+						HWND hwnd = CreateWindowW(L"bgfx"
+							, UTF8ToUTF16(msg->m_title.c_str()).data()
 							, WS_OVERLAPPEDWINDOW|WS_VISIBLE
 							, msg->m_x
 							, msg->m_y
@@ -557,7 +569,7 @@ namespace entry
 							, msg->m_height
 							, NULL
 							, NULL
-							, (HINSTANCE)GetModuleHandle(NULL)
+							, (HINSTANCE)GetModuleHandleW(NULL)
 							, 0
 							);
 						clear(hwnd);
@@ -590,7 +602,7 @@ namespace entry
 				case WM_USER_WINDOW_SET_TITLE:
 					{
 						Msg* msg = (Msg*)_lparam;
-						SetWindowTextA(m_hwnd[_wparam], msg->m_title.c_str() );
+						SetWindowTextW(m_hwnd[_wparam], UTF8ToUTF16(msg->m_title.c_str()).data() );
 						delete msg;
 					}
 					break;
@@ -743,7 +755,7 @@ namespace entry
 							HWND parent = GetWindow(_hwnd, GW_OWNER);
 							if (NULL != parent)
 							{
-								PostMessage(parent, _id, _wparam, _lparam);
+								PostMessageW(parent, _id, _wparam, _lparam);
 							}
 						}
 					}
@@ -842,20 +854,36 @@ namespace entry
 
 				case WM_CHAR:
 					{
+						WCHAR utf16[2] = { (WCHAR)_wparam };
 						uint8_t utf8[4] = {};
-						uint8_t len = (uint8_t)WideCharToMultiByte(CP_UTF8
-											, 0
-											, (LPCWSTR)&_wparam
-											, 1
-											, (LPSTR)utf8
-											, BX_COUNTOF(utf8)
-											, NULL
-											, NULL
-											);
-						if (0 != len)
-						{
-							WindowHandle handle = findHandle(_hwnd);
-							m_eventQueue.postCharEvent(handle, len, utf8);
+
+						if (utf16[0] >= 0xD800 && utf16[0] <= 0xDBFF) {
+							m_surrogate = utf16[0];
+						} else {
+							int utf16_len;
+							if (utf16[0] >= 0xDC00 && utf16[0] <= 0xDFFF) {
+								utf16[1] = utf16[0];
+								utf16[0] = m_surrogate;
+								m_surrogate = 0;
+								utf16_len = 2;
+							} else {
+								utf16_len = 1;
+							}
+
+							uint8_t len = (uint8_t)WideCharToMultiByte(CP_UTF8
+												, 0
+												, utf16
+												, utf16_len
+												, (LPSTR)utf8
+												, BX_COUNTOF(utf8)
+												, NULL
+												, NULL
+												);
+							if (0 != len)
+							{
+								WindowHandle handle = findHandle(_hwnd);
+								m_eventQueue.postCharEvent(handle, len, utf8);
+							}
 						}
 					}
 					break;
@@ -864,8 +892,10 @@ namespace entry
 					{
 						HDROP drop = (HDROP)_wparam;
 						char tmp[bx::kMaxFilePath];
-						uint32_t result = DragQueryFileA(drop, 0, tmp, sizeof(tmp) );
+						WCHAR utf16[bx::kMaxFilePath];
+						uint32_t result = DragQueryFileW(drop, 0, utf16, bx::kMaxFilePath);
 						BX_UNUSED(result);
+						WideCharToMultiByte(CP_UTF8, 0, utf16, -1, tmp, bx::kMaxFilePath, NULL, NULL);
 						WindowHandle handle = findHandle(_hwnd);
 						m_eventQueue.postDropFileEvent(handle, tmp);
 					}
@@ -876,7 +906,7 @@ namespace entry
 				}
 			}
 
-			return DefWindowProc(_hwnd, _id, _wparam, _lparam);
+			return DefWindowProcW(_hwnd, _id, _wparam, _lparam);
 		}
 
 		WindowHandle findHandle(HWND _hwnd)
@@ -921,7 +951,7 @@ namespace entry
 			if (m_frame)
 			{
 				GetWindowRect(_hwnd, &m_rect);
-				m_style = GetWindowLong(_hwnd, GWL_STYLE);
+				m_style = GetWindowLongW(_hwnd, GWL_STYLE);
 			}
 
 			if (_windowFrame)
@@ -934,13 +964,13 @@ namespace entry
 				HMONITOR monitor = MonitorFromWindow(_hwnd, MONITOR_DEFAULTTONEAREST);
 				MONITORINFO mi;
 				mi.cbSize = sizeof(mi);
-				GetMonitorInfo(monitor, &mi);
+				GetMonitorInfoW(monitor, &mi);
 				newrect = mi.rcMonitor;
 				rect = mi.rcMonitor;
 				m_aspectRatio = float(newrect.right  - newrect.left)/float(newrect.bottom - newrect.top);
 			}
 
-			SetWindowLong(_hwnd, GWL_STYLE, style);
+			SetWindowLongW(_hwnd, GWL_STYLE, style);
 			uint32_t prewidth  = newrect.right - newrect.left;
 			uint32_t preheight = newrect.bottom - newrect.top;
 			AdjustWindowRect(&newrect, style, FALSE);
@@ -1015,6 +1045,7 @@ namespace entry
 		static LRESULT CALLBACK wndProc(HWND _hwnd, UINT _id, WPARAM _wparam, LPARAM _lparam);
 
 		EventQueue m_eventQueue;
+		WCHAR m_surrogate;
 		bx::Mutex m_lock;
 
 		bx::HandleAllocT<ENTRY_CONFIG_MAX_WINDOWS> m_windowAlloc;
@@ -1078,7 +1109,7 @@ namespace entry
 			msg->m_height = _height;
 			msg->m_title  = _title;
 			msg->m_flags  = _flags;
-			PostMessage(s_ctx.m_hwnd[0], WM_USER_WINDOW_CREATE, handle.idx, (LPARAM)msg);
+			PostMessageW(s_ctx.m_hwnd[0], WM_USER_WINDOW_CREATE, handle.idx, (LPARAM)msg);
 		}
 
 		return handle;
@@ -1088,7 +1119,7 @@ namespace entry
 	{
 		if (UINT16_MAX != _handle.idx)
 		{
-			PostMessage(s_ctx.m_hwnd[0], WM_USER_WINDOW_DESTROY, _handle.idx, 0);
+			PostMessageW(s_ctx.m_hwnd[0], WM_USER_WINDOW_DESTROY, _handle.idx, 0);
 
 			bx::MutexScope scope(s_ctx.m_lock);
 			s_ctx.m_windowAlloc.free(_handle.idx);
@@ -1100,19 +1131,19 @@ namespace entry
 		Msg* msg = new Msg;
 		msg->m_x = _x;
 		msg->m_y = _y;
-		PostMessage(s_ctx.m_hwnd[0], WM_USER_WINDOW_SET_POS, _handle.idx, (LPARAM)msg);
+		PostMessageW(s_ctx.m_hwnd[0], WM_USER_WINDOW_SET_POS, _handle.idx, (LPARAM)msg);
 	}
 
 	void setWindowSize(WindowHandle _handle, uint32_t _width, uint32_t _height)
 	{
-		PostMessage(s_ctx.m_hwnd[0], WM_USER_WINDOW_SET_SIZE, _handle.idx, (_height<<16) | (_width&0xffff) );
+		PostMessageW(s_ctx.m_hwnd[0], WM_USER_WINDOW_SET_SIZE, _handle.idx, (_height<<16) | (_width&0xffff) );
 	}
 
 	void setWindowTitle(WindowHandle _handle, const char* _title)
 	{
 		Msg* msg = new Msg;
 		msg->m_title = _title;
-		PostMessage(s_ctx.m_hwnd[0], WM_USER_WINDOW_SET_TITLE, _handle.idx, (LPARAM)msg);
+		PostMessageW(s_ctx.m_hwnd[0], WM_USER_WINDOW_SET_TITLE, _handle.idx, (LPARAM)msg);
 	}
 
 	void setWindowFlags(WindowHandle _handle, uint32_t _flags, bool _enabled)
@@ -1120,24 +1151,24 @@ namespace entry
 		Msg* msg = new Msg;
 		msg->m_flags = _flags;
 		msg->m_flagsEnabled = _enabled;
-		PostMessage(s_ctx.m_hwnd[0], WM_USER_WINDOW_SET_FLAGS, _handle.idx, (LPARAM)msg);
+		PostMessageW(s_ctx.m_hwnd[0], WM_USER_WINDOW_SET_FLAGS, _handle.idx, (LPARAM)msg);
 	}
 
 	void toggleFullscreen(WindowHandle _handle)
 	{
-		PostMessage(s_ctx.m_hwnd[0], WM_USER_WINDOW_TOGGLE_FRAME, _handle.idx, 0);
+		PostMessageW(s_ctx.m_hwnd[0], WM_USER_WINDOW_TOGGLE_FRAME, _handle.idx, 0);
 	}
 
 	void setMouseLock(WindowHandle _handle, bool _lock)
 	{
-		PostMessage(s_ctx.m_hwnd[0], WM_USER_WINDOW_MOUSE_LOCK, _handle.idx, _lock);
+		PostMessageW(s_ctx.m_hwnd[0], WM_USER_WINDOW_MOUSE_LOCK, _handle.idx, _lock);
 	}
 
 	int32_t MainThreadEntry::threadFunc(bx::Thread* /*_thread*/, void* _userData)
 	{
 		MainThreadEntry* self = (MainThreadEntry*)_userData;
 		int32_t result = main(self->m_argc, self->m_argv);
-		PostMessage(s_ctx.m_hwnd[0], WM_QUIT, 0, 0);
+		PostMessageW(s_ctx.m_hwnd[0], WM_QUIT, 0, 0);
 		return result;
 	}