Merged Daniel's Google Summer of Code work from SDL-gsoc2010_IME
authorSam Lantinga <slouken@libsdl.org>
Sun, 22 Aug 2010 12:39:27 -0700
changeset 4763 518d1679d2d0
parent 4762 833a225613e2 (current diff)
parent 4761 bb2e32f5a556 (diff)
child 4764 102675835e08
Merged Daniel's Google Summer of Code work from SDL-gsoc2010_IME
include/SDL_stdinc.h
src/SDL_compat.c
src/events/SDL_keyboard.c
src/video/SDL_sysvideo.h
src/video/SDL_video.c
src/video/win32/SDL_win32events.c
src/video/win32/SDL_win32keyboard.c
src/video/win32/SDL_win32video.c
src/video/win32/SDL_win32video.h
src/video/win32/SDL_win32window.c
test/testime.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EXCLUDE/GLIMM/GLIMM.sln	Sun Aug 22 12:39:27 2010 -0700
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GLIMM", "GLIMM.vcproj", "{F21B830F-20A9-4473-B67A-21D1743C6E19}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{F21B830F-20A9-4473-B67A-21D1743C6E19}.Debug|Win32.ActiveCfg = Debug|Win32
+		{F21B830F-20A9-4473-B67A-21D1743C6E19}.Debug|Win32.Build.0 = Debug|Win32
+		{F21B830F-20A9-4473-B67A-21D1743C6E19}.Release|Win32.ActiveCfg = Release|Win32
+		{F21B830F-20A9-4473-B67A-21D1743C6E19}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EXCLUDE/GLIMM/GLIMM.vcproj	Sun Aug 22 12:39:27 2010 -0700
@@ -0,0 +1,233 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="GLIMM"
+	ProjectGUID="{F21B830F-20A9-4473-B67A-21D1743C6E19}"
+	RootNamespace="GLIMM"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="196613"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)bin"
+			IntermediateDirectory="obj\$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="imm32.lib"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)bin"
+			IntermediateDirectory="obj\$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="imm32.lib"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\src\App.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\IMM.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\Main.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\Video_Mode.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\Window.cpp"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath=".\include\App.hpp"
+				>
+			</File>
+			<File
+				RelativePath=".\include\IMM.hpp"
+				>
+			</File>
+			<File
+				RelativePath=".\include\Video_Mode.hpp"
+				>
+			</File>
+			<File
+				RelativePath=".\include\Window.hpp"
+				>
+			</File>
+			<File
+				RelativePath=".\include\Window_Listener.hpp"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EXCLUDE/GLIMM/include/App.hpp	Sun Aug 22 12:39:27 2010 -0700
@@ -0,0 +1,37 @@
+#ifndef APP_HPP
+#define APP_HPP
+
+#include "Window.hpp"
+
+class App : public Window_Listener
+{
+public:
+	App();
+	virtual ~App();
+
+	void Initialize();
+	void Finalize();
+
+	void Run();
+
+	virtual void On_Close();
+	virtual void On_Key_Down(int Key);
+	virtual void On_Key_Up(int Key);
+	virtual void On_Char(unsigned int Char);
+	virtual void On_Resized(unsigned int Width, unsigned int Height);
+	virtual void On_Mouse_Button_Down(Mouse_Button Button);
+
+private:
+	void Update();
+	void Draw();
+
+	static const int Width = 800;
+	static const int Height = 600;
+	static const int Bits_Per_Pixel = 32;
+	static const bool Fullscreen = true;
+
+	Window my_Window;
+	bool my_Done;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EXCLUDE/GLIMM/include/IMM.hpp	Sun Aug 22 12:39:27 2010 -0700
@@ -0,0 +1,41 @@
+#ifndef IMM_HPP
+#define IMM_HPP
+
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#include <msctf.h>
+
+class IMM
+{
+public:
+	IMM();
+	~IMM();
+
+	void Initialize(HWND Window);
+	void Finalize();
+
+	LRESULT Handle_Message(HWND Window, UINT Message, WPARAM wParam, LPARAM lParam, bool &Ate);
+
+	void Enable();
+	void Disable();
+	bool Is_Enabled();
+	void Toggle();
+
+	void Focus_Gained();
+	void Focus_Lost();
+
+private:
+	void Update_Input_Locale();
+	void Cancel_Composition();
+	void Input_Language_Changed();
+
+	bool my_COM_Initialized;
+	ITfThreadMgr *my_Thread_Manager;
+	HWND my_Window;
+	HIMC my_Context;
+	HKL my_HKL;
+	bool my_Vertical_Candidates;
+	bool my_Enabled;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EXCLUDE/GLIMM/include/Video_Mode.hpp	Sun Aug 22 12:39:27 2010 -0700
@@ -0,0 +1,30 @@
+#ifndef VIDEO_MODE_HPP
+#define VIDEO_MODE_HPP
+
+#include <cstddef>
+
+class Video_Mode
+{
+public:
+	Video_Mode();
+	Video_Mode(unsigned int The_Width, unsigned int The_Height, unsigned int The_Bits_Per_Pixel);
+
+	static Video_Mode Get_Desktop_Mode();
+
+	static std::size_t Get_Mode_Count();
+	static Video_Mode Get_Mode(std::size_t Index);
+
+	bool Is_Valid() const;
+
+	bool operator==(const Video_Mode &Mode) const;
+	bool operator!=(const Video_Mode &Mode) const;
+
+	unsigned int Width;
+	unsigned int Height;
+	unsigned int Bits_Per_Pixel;
+
+private:
+	static void Initialize_Modes();
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EXCLUDE/GLIMM/include/Window.hpp	Sun Aug 22 12:39:27 2010 -0700
@@ -0,0 +1,63 @@
+#ifndef WINDOW_HPP
+#define WINDOW_HPP
+
+#include <string>
+
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+
+#include "Video_Mode.hpp"
+#include "Window_Listener.hpp"
+#include "IMM.hpp"
+
+class Window
+{
+public:
+	Window();
+	~Window();
+
+	void Initialize(const std::wstring &Title, const Video_Mode &Mode, bool Fullscreen);
+	void Finalize();
+
+	void Set_Listener(Window_Listener *Listener);
+
+	void Show();
+	void Hide();
+
+	void Handle_Events();
+	void Display();
+
+	void Show_Cursor();
+	void Hide_Cursor();
+
+	HWND Get_Handle();
+	IMM &Get_IMM();
+
+private:
+	static const wchar_t *Window_Class_Name;
+
+	void Register_Class();
+	void Unregister_Class();
+
+	void Create_Window(const std::wstring &Title, const Video_Mode &Mode, bool Fullscreen);
+	void Destroy_Window();
+
+	void Create_Context(const Video_Mode &Mode);
+	void Destroy_Context();
+
+	void Switch_To_Fullscreen(const Video_Mode &Mode);
+
+	LRESULT Handle_Message(HWND Handle, UINT Message, WPARAM wParam, LPARAM lParam);
+	static LRESULT CALLBACK Window_Procedure(HWND Handle, UINT Message, WPARAM wParam, LPARAM lParam);
+
+	HWND my_Handle;
+	Video_Mode my_Video_Mode;
+	bool my_Fullscreen;
+	HDC my_Device_Context;
+	HGLRC my_GL_Context;
+	bool my_Class_Registered;
+	Window_Listener *my_Listener;
+	IMM my_IMM;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EXCLUDE/GLIMM/include/Window_Listener.hpp	Sun Aug 22 12:39:27 2010 -0700
@@ -0,0 +1,23 @@
+#ifndef WINDOW_LISTENER_HPP
+#define WINDOW_LISTENER_HPP
+
+enum Mouse_Button
+{
+	Mouse_Button_Left,
+	Mouse_Button_Right
+};
+
+class Window_Listener
+{
+public:
+	virtual void On_Close(){}
+	virtual void On_Key_Down(int Key){}
+	virtual void On_Key_Up(int Key){}
+	virtual void On_Char(unsigned int Char){}
+	virtual void On_Resized(unsigned int Width, unsigned int Height){}
+	virtual void On_Mouse_Button_Down(Mouse_Button Button){}
+	virtual void On_Mouse_Button_Up(Mouse_Button Button){}
+
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EXCLUDE/GLIMM/src/App.cpp	Sun Aug 22 12:39:27 2010 -0700
@@ -0,0 +1,113 @@
+#include "App.hpp"
+#include <GL/gl.h>
+#include <GL/glu.h>
+
+#pragma comment(lib, "glu32.lib")
+
+GLfloat Rotation = 0.0f;
+
+App::App() : my_Done(false)
+{
+
+}
+
+App::~App()
+{
+	Finalize();
+}
+
+void App::Initialize()
+{
+	Finalize();
+
+	my_Window.Initialize(L"GLIMM", Video_Mode(Width, Height, Bits_Per_Pixel), Fullscreen);
+	my_Window.Set_Listener(this);
+	my_Window.Show();
+	my_Window.Hide_Cursor();
+}
+
+void App::Finalize()
+{
+	my_Window.Finalize();
+}
+
+void App::Run()
+{
+	Initialize();
+	while (!my_Done)
+	{
+		my_Window.Handle_Events();
+
+		Update();
+		Draw();
+		my_Window.Display();
+	}
+}
+
+void App::On_Close()
+{
+	my_Done = true;
+	my_Window.Hide();
+}
+
+void App::On_Key_Down(int Key)
+{
+	switch (Key)
+	{
+	case VK_ESCAPE:
+		On_Close();
+		break;
+	}
+}
+
+void App::On_Key_Up(int Key)
+{
+
+}
+
+void App::On_Char(unsigned int Char)
+{
+	printf("Char: U+%04X\n", Char);
+}
+
+void App::On_Resized(unsigned int Width, unsigned int Height)
+{
+	glViewport(0, 0, Width, Height);
+	glMatrixMode(GL_PROJECTION);
+	glLoadIdentity();
+
+	glMatrixMode(GL_MODELVIEW);
+	glLoadIdentity();
+}
+
+void App::On_Mouse_Button_Down(Mouse_Button Button)
+{
+	switch (Button)
+	{
+	case Mouse_Button_Left:
+		my_Window.Get_IMM().Toggle();
+		break;
+	}
+}
+
+void App::Update()
+{
+	Rotation += 0.2f;
+}
+
+void App::Draw()
+{
+	glClear(GL_COLOR_BUFFER_BIT);
+
+	glLoadIdentity();
+	glRotatef(Rotation, 0.0f, 0.0f, -1.0f);
+
+	glBegin(GL_TRIANGLES);
+		glColor3f(0.7f, 0.0f, 0.0f);
+		glVertex3f(0.0f, 0.5f, 0.0f);
+		glColor3f(0.0f, 0.7f, 0.0f);
+		glVertex3f(-0.5f, -0.5f, 0.0f);
+		glColor3f(0.0f, 0.0f, 0.7f);
+		glVertex3f(0.5f, -0.5f, 0.0f);
+	glEnd();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EXCLUDE/GLIMM/src/IMM.cpp	Sun Aug 22 12:39:27 2010 -0700
@@ -0,0 +1,237 @@
+#include "IMM.hpp"
+#include <stdexcept>
+
+IMM::IMM() : my_COM_Initialized(false),
+			 my_Thread_Manager(0),
+			 my_Window(0),
+			 my_Context(0),
+			 my_HKL(0),
+			 my_Vertical_Candidates(false),
+			 my_Enabled(false)
+{
+
+}
+
+IMM::~IMM()
+{
+	Finalize();
+}
+
+void IMM::Initialize(HWND Window)
+{
+	Finalize();
+
+	my_Window = Window;
+
+	if (SUCCEEDED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)))
+	{
+		my_COM_Initialized = true;
+		if (SUCCEEDED(CoCreateInstance(CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, IID_ITfThreadMgr, reinterpret_cast<LPVOID *>(&my_Thread_Manager))))
+		{
+			ITfDocumentMgr *Document_Manager = 0;
+			if (SUCCEEDED(my_Thread_Manager->AssociateFocus(Window, NULL, &Document_Manager)))
+			{
+				if (Document_Manager)
+					Document_Manager->Release();
+			}
+			else
+				printf("Warning: ITfThreadMgr->AssociateFocus failed\n");
+		}
+		else
+			printf("Warning: Failed to create ITfThreadMgr instance\n");
+	}
+	else
+		printf("Warning: Failed to initialize COM\n");
+
+	ImmDisableTextFrameService((DWORD)-1);
+
+	my_Context = ImmGetContext(my_Window);
+	ImmReleaseContext(my_Window, my_Context);
+	if (!my_Context)
+		throw std::runtime_error("No context (No IME installed?)");
+
+	Update_Input_Locale();
+	Cancel_Composition();
+	Disable();
+}
+
+void IMM::Finalize()
+{
+	if (my_Thread_Manager)
+	{
+		my_Thread_Manager->Release();
+		my_Thread_Manager = 0;
+	}
+	if (my_COM_Initialized)
+	{
+		CoUninitialize();
+		my_COM_Initialized = false;
+	}
+}
+
+#define GET_LANG(hkl) LOWORD((hkl))
+#define GET_PRIMLANG(hkl) ((WORD)PRIMARYLANGID(GET_LANG((hkl))))
+#define GET_SUBLANG(hkl) SUBLANGID(GET_LANG((hkl)))
+
+void IMM::Update_Input_Locale()
+{
+	static HKL Previous_HKL = 0;
+	my_HKL = GetKeyboardLayout(0);
+	if (Previous_HKL == my_HKL)
+		return;
+
+	Previous_HKL = my_HKL;
+	my_Vertical_Candidates = false;
+	switch (GET_PRIMLANG(my_HKL))
+	{
+	case LANG_CHINESE:
+		my_Vertical_Candidates = true;
+		switch (GET_SUBLANG(my_HKL))
+		{
+		case SUBLANG_CHINESE_SIMPLIFIED:
+			my_Vertical_Candidates = false;
+			break;
+		}
+		break;
+	case LANG_JAPANESE:
+		my_Vertical_Candidates = true;
+		break;
+	}
+}
+
+LRESULT IMM::Handle_Message(HWND Window, UINT Message, WPARAM wParam, LPARAM lParam, bool &Ate)
+{
+	Ate = false;
+	switch (Message)
+	{
+	case WM_INPUTLANGCHANGE:
+		Input_Language_Changed();
+		break;
+	case WM_IME_SETCONTEXT:
+		lParam = 0;
+		break;
+	case WM_IME_STARTCOMPOSITION:
+		Ate = true;
+		break;
+	case WM_IME_COMPOSITION:
+		{
+			Ate = true;
+			HIMC Context = ImmGetContext(Window);
+			if (!Context)
+				break;
+
+			if (lParam & GCS_RESULTSTR)
+			{
+				LONG Length = ImmGetCompositionStringW(Context, GCS_RESULTSTR, 0, 0);
+				std::wstring Composition(Length / sizeof(wchar_t), 0);
+				Length = ImmGetCompositionStringW(Context, GCS_RESULTSTR, &Composition[0], Composition.size() * sizeof(Composition[0]));
+				printf("GCS_RESULTSTR: ");
+				for (LONG i = 0; i < Length / sizeof(wchar_t); ++i)
+					printf("U+%04X ", Composition[i]);
+
+				printf("\n");
+			}
+			if (lParam & GCS_COMPSTR)
+			{
+				LONG Length = ImmGetCompositionStringW(Context, GCS_COMPSTR, 0, 0);
+				std::wstring Composition(Length / sizeof(wchar_t), 0);
+				Length = ImmGetCompositionStringW(Context, GCS_COMPSTR, &Composition[0], Composition.size() * sizeof(Composition[0]));
+				printf("GCS_COMPSTR: ");
+				for (LONG i = 0; i < Length / sizeof(wchar_t); ++i)
+					printf("U+%04X ", Composition[i]);
+
+				printf("\n");
+			}
+			ImmReleaseContext(Window, Context);
+		}
+		break;
+	case WM_IME_ENDCOMPOSITION:
+		break;
+	case WM_IME_NOTIFY:
+		switch (wParam)
+		{
+		case IMN_SETCONVERSIONMODE:
+
+			break;
+		case IMN_SETOPENSTATUS:
+			Update_Input_Locale();
+			break;
+		case IMN_OPENCANDIDATE:
+		case IMN_CHANGECANDIDATE:
+			Ate = true;
+			break;
+		case IMN_CLOSECANDIDATE:
+			Ate = true;
+			break;
+		default:
+			Ate = true;
+			break;
+		}
+		break;
+	}
+	return 0;
+}
+
+void IMM::Enable()
+{
+	ImmAssociateContext(my_Window, my_Context);
+	Update_Input_Locale();
+	my_Enabled = true;
+	printf("* Enabled\n");
+}
+
+void IMM::Disable()
+{
+	ImmAssociateContext(my_Window, 0);
+	my_Enabled = false;
+	printf("* Disabled\n");
+}
+
+bool IMM::Is_Enabled()
+{
+	return my_Enabled;
+}
+
+void IMM::Toggle()
+{
+	if (my_Enabled)
+		Disable();
+	else
+		Enable();
+}
+
+void IMM::Focus_Gained()
+{
+	if (my_Enabled)
+		Enable();
+}
+
+void IMM::Focus_Lost()
+{
+	bool Enabled = my_Enabled;
+	Cancel_Composition();
+	Disable();
+	my_Enabled = Enabled;
+}
+
+void IMM::Cancel_Composition()
+{
+	HIMC hIMC = ImmGetContext(my_Window);
+	if (!hIMC)
+		return;
+
+	ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
+	ImmNotifyIME(hIMC, NI_CLOSECANDIDATE, 0, 0);
+	ImmReleaseContext(my_Window, hIMC);
+}
+
+void IMM::Input_Language_Changed()
+{
+	Update_Input_Locale();
+	HWND hwndImeDef = ImmGetDefaultIMEWnd(my_Window);
+	if (hwndImeDef)
+	{
+		SendMessageA(hwndImeDef, WM_IME_CONTROL, IMC_OPENSTATUSWINDOW, 0);
+		SendMessageA(hwndImeDef, WM_IME_CONTROL, IMC_CLOSESTATUSWINDOW, 0);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EXCLUDE/GLIMM/src/Main.cpp	Sun Aug 22 12:39:27 2010 -0700
@@ -0,0 +1,24 @@
+#include "App.hpp"
+#include <stdexcept>
+
+int main(int argc, char *argv[])
+{
+	int Result = EXIT_SUCCESS;
+	try
+	{
+		App theApp;
+		theApp.Run();
+	}
+	catch (const std::exception& e)
+	{
+		printf("Error: %s\n", e.what());
+		Result = EXIT_FAILURE;
+	}
+	catch (...)
+	{
+		printf("Unhandled exception\n");
+		Result = EXIT_FAILURE;
+	}
+	system("PAUSE");
+	return Result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EXCLUDE/GLIMM/src/Video_Mode.cpp	Sun Aug 22 12:39:27 2010 -0700
@@ -0,0 +1,100 @@
+#include "Video_Mode.hpp"
+#include <vector>
+#include <algorithm>
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+
+namespace
+{
+
+	typedef std::vector<Video_Mode> Video_Mode_List;
+	Video_Mode_List Supported_Modes;
+
+	struct Compare_Modes
+	{
+		bool operator()(const Video_Mode &Mode_1, const Video_Mode &Mode_2) const
+		{
+			if (Mode_1.Bits_Per_Pixel > Mode_2.Bits_Per_Pixel)
+				return true;
+			else if (Mode_1.Bits_Per_Pixel < Mode_2.Bits_Per_Pixel)
+				return false;
+			else if (Mode_1.Width > Mode_2.Width)
+				return true;
+			else if (Mode_1.Width < Mode_2.Width)
+				return false;
+			else
+				return Mode_1.Height > Mode_2.Height;
+		}
+	};
+
+}
+
+Video_Mode::Video_Mode() : Width(0),
+						   Height(0),
+						   Bits_Per_Pixel(0)
+{
+
+}
+
+Video_Mode::Video_Mode(unsigned int The_Width, unsigned int The_Height, unsigned int The_Bits_Per_Pixel)
+	: Width(The_Width),
+	  Height(The_Height),
+	  Bits_Per_Pixel(The_Bits_Per_Pixel)
+{
+
+}
+
+Video_Mode Video_Mode::Get_Desktop_Mode()
+{
+	DEVMODE Device_Mode = {0};
+	Device_Mode.dmSize = sizeof(Device_Mode);
+	EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &Device_Mode);
+	return Video_Mode(Device_Mode.dmPelsWidth, Device_Mode.dmPelsHeight, Device_Mode.dmBitsPerPel);
+}
+
+std::size_t Video_Mode::Get_Mode_Count()
+{
+	Initialize_Modes();
+	return Supported_Modes.size();
+}
+
+Video_Mode Video_Mode::Get_Mode(std::size_t Index)
+{
+	Initialize_Modes();
+	return Supported_Modes[Index];
+}
+
+bool Video_Mode::Is_Valid() const
+{
+	Initialize_Modes();
+	return Supported_Modes.end() != std::find(Supported_Modes.begin(), Supported_Modes.end(), *this);
+}
+
+bool Video_Mode::operator==(const Video_Mode &Mode) const
+{
+	return (Width == Mode.Width
+		&&  Height == Mode.Height
+		&&  Bits_Per_Pixel == Mode.Bits_Per_Pixel);
+}
+
+bool Video_Mode::operator!=(const Video_Mode &Mode) const
+{
+	return !(*this == Mode);
+}
+
+void Video_Mode::Initialize_Modes()
+{
+	static bool Initialized = false;
+	if (!Initialized)
+	{
+		DEVMODE Device_Mode = {0};
+		Device_Mode.dmSize = sizeof(Device_Mode);
+		for (std::size_t i = 0; 0 != EnumDisplaySettings(NULL, i, &Device_Mode); ++i)
+		{
+			Video_Mode Mode(Device_Mode.dmPelsWidth, Device_Mode.dmPelsHeight, Device_Mode.dmBitsPerPel);
+			if (Supported_Modes.end() == std::find(Supported_Modes.begin(), Supported_Modes.end(), Mode))
+				Supported_Modes.push_back(Mode);
+		}
+		std::sort(Supported_Modes.begin(), Supported_Modes.end(), Compare_Modes());
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EXCLUDE/GLIMM/src/Window.cpp	Sun Aug 22 12:39:27 2010 -0700
@@ -0,0 +1,317 @@
+#include "Window.hpp"
+#include <gl/GL.h>
+
+#pragma comment(lib, "opengl32.lib")
+
+const wchar_t *Window::Window_Class_Name = L"GLTSF";
+
+Window::Window() : my_Handle(0),
+				   my_Device_Context(0),
+				   my_GL_Context(0),
+				   my_Class_Registered(false),
+				   my_Listener(0)
+{
+
+}
+
+Window::~Window()
+{
+	Finalize();
+	Show_Cursor();
+}
+
+void Window::Initialize(const std::wstring &Title, const Video_Mode &Mode, bool Fullscreen)
+{
+	Finalize();
+
+	my_Video_Mode = Mode;
+	if (!my_Video_Mode.Is_Valid())
+		throw std::runtime_error("Invalid video mode");
+
+	my_Fullscreen = Fullscreen;
+	Register_Class();
+	Create_Window(Title, Mode, Fullscreen);
+	Show();
+	my_IMM.Initialize(my_Handle);
+}
+
+void Window::Finalize()
+{
+	my_IMM.Finalize();
+	Destroy_Window();
+	Unregister_Class();
+}
+
+void Window::Set_Listener(Window_Listener *Listener)
+{
+	my_Listener = Listener;
+}
+
+void Window::Show()
+{
+	if (my_Handle)
+		ShowWindow(my_Handle, SW_SHOW);
+}
+
+void Window::Hide()
+{
+	if (my_Handle)
+		ShowWindow(my_Handle, SW_HIDE);
+}
+
+void Window::Handle_Events()
+{
+	MSG Message = {0};
+	while (PeekMessageW(&Message, NULL, 0, 0, PM_REMOVE))
+	{
+		TranslateMessage(&Message);
+		DispatchMessageW(&Message);
+	}
+}
+
+void Window::Display()
+{
+	if (my_Device_Context && my_GL_Context)
+		SwapBuffers(my_Device_Context);
+}
+
+void Window::Show_Cursor()
+{
+	ShowCursor(TRUE);
+}
+
+void Window::Hide_Cursor()
+{
+	ShowCursor(FALSE);
+}
+
+HWND Window::Get_Handle()
+{
+	return my_Handle;
+}
+
+IMM & Window::Get_IMM()
+{
+	return my_IMM;
+}
+
+void Window::Register_Class()
+{
+	WNDCLASSEXW Window_Class = {0};
+	Window_Class.cbSize = sizeof(Window_Class);
+	Window_Class.style = 0;
+	Window_Class.lpfnWndProc = &Window::Window_Procedure;
+	Window_Class.cbClsExtra = 0;
+	Window_Class.cbWndExtra = 0;
+	Window_Class.hInstance = GetModuleHandle(NULL);
+	Window_Class.hIcon = NULL;
+	Window_Class.hCursor = NULL;
+	Window_Class.hbrBackground = NULL;
+	Window_Class.lpszMenuName = NULL;
+	Window_Class.lpszClassName = Window_Class_Name;
+	Window_Class.hIconSm = NULL;
+	if (0 == RegisterClassExW(&Window_Class))
+		throw std::runtime_error("Failed to register window class");
+
+	my_Class_Registered = true;
+}
+
+void Window::Unregister_Class()
+{
+	if (my_Class_Registered)
+	{
+		if (0 == UnregisterClassW(Window_Class_Name, GetModuleHandle(NULL)))
+			printf("Warning: Failed to unregister window class\n");
+
+		my_Class_Registered = false;
+	}
+}
+
+void Window::Create_Window(const std::wstring &Title, const Video_Mode &Mode, bool Fullscreen)
+{
+	HDC Screen_DC = GetDC(NULL);
+	int Left = (GetDeviceCaps(Screen_DC, HORZRES) - my_Video_Mode.Width) / 2;
+	int Top = (GetDeviceCaps(Screen_DC, VERTRES) - my_Video_Mode.Height) / 2;
+	int Width = my_Video_Mode.Width;
+	int Height = my_Video_Mode.Height;
+	ReleaseDC(NULL, Screen_DC);
+
+	DWORD Style = WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;
+	if (!my_Fullscreen)
+	{
+		RECT Rect = {0, 0, Width, Height};
+		AdjustWindowRect(&Rect, Style, false);
+		Width = Rect.right - Rect.left;
+		Height = Rect.bottom - Rect.top;
+	}
+	my_Handle = CreateWindowW(Window_Class_Name, Title.c_str(), Style, Left, Top, Width, Height, NULL, NULL, GetModuleHandle(NULL), this);
+	if (!my_Handle)
+		throw std::runtime_error("Failed to create window");
+
+	if (Fullscreen)
+		Switch_To_Fullscreen(Mode);
+
+	Create_Context(Mode);
+
+	RECT Rect = {0};
+	GetClientRect(my_Handle, &Rect);
+	//TODO: ...
+}
+
+void Window::Destroy_Window()
+{
+	Destroy_Context();
+	if (my_Handle)
+	{
+		DestroyWindow(my_Handle);
+		my_Handle = 0;
+
+		if (my_Fullscreen)
+			ChangeDisplaySettings(NULL, 0);
+	}
+}
+
+void Window::Create_Context(const Video_Mode &Mode)
+{
+	my_Device_Context = GetDC(my_Handle);
+	if (!my_Device_Context)
+		throw std::runtime_error("Failed to get device context");
+
+	PIXELFORMATDESCRIPTOR Pixel_Descriptor = {0};
+	Pixel_Descriptor.nSize = sizeof(Pixel_Descriptor);
+	Pixel_Descriptor.nVersion = 1;
+	Pixel_Descriptor.iLayerType = PFD_MAIN_PLANE;
+	Pixel_Descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
+	Pixel_Descriptor.iPixelType = PFD_TYPE_RGBA;
+	Pixel_Descriptor.cColorBits = static_cast<BYTE>(Mode.Bits_Per_Pixel);
+	Pixel_Descriptor.cDepthBits = 24;
+	Pixel_Descriptor.cStencilBits = 8;
+	Pixel_Descriptor.cAlphaBits = Mode.Bits_Per_Pixel == 32 ? 8 : 0;
+
+	int Best_Format = ChoosePixelFormat(my_Device_Context, &Pixel_Descriptor);
+	if (0 == Best_Format)
+		throw std::runtime_error("Failed to find suitable pixel format");
+
+	PIXELFORMATDESCRIPTOR Actual_Format = {0};
+	Actual_Format.nSize = sizeof(Actual_Format);
+	Actual_Format.nVersion = 1;
+	DescribePixelFormat(my_Device_Context, Best_Format, sizeof(Actual_Format), &Actual_Format);
+	if (!SetPixelFormat(my_Device_Context, Best_Format, &Actual_Format))
+		throw std::runtime_error("Failed to set device pixel format");
+
+	my_GL_Context = wglCreateContext(my_Device_Context);
+	if (!my_GL_Context)
+		throw std::runtime_error("Failed to create OpenGL context");
+
+	wglMakeCurrent(my_Device_Context, my_GL_Context);
+}
+
+void Window::Destroy_Context()
+{
+	if (my_GL_Context)
+	{
+		wglDeleteContext(my_GL_Context);
+		my_GL_Context = 0;
+	}
+	if (my_Device_Context)
+	{
+		ReleaseDC(my_Handle, my_Device_Context);
+		my_Device_Context = 0;
+	}
+}
+
+void Window::Switch_To_Fullscreen(const Video_Mode &Mode)
+{
+	DEVMODE Device_Mode = {0};
+	Device_Mode.dmSize = sizeof(Device_Mode);
+	Device_Mode.dmPelsWidth = Mode.Width;
+	Device_Mode.dmPelsHeight = Mode.Height;
+	Device_Mode.dmBitsPerPel = Mode.Bits_Per_Pixel;
+	Device_Mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
+
+	if (DISP_CHANGE_SUCCESSFUL != ChangeDisplaySettings(&Device_Mode, CDS_FULLSCREEN))
+		throw std::runtime_error("Failed to change to fullscreen mode");
+
+	SetWindowLong(my_Handle, GWL_STYLE, WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
+	SetWindowLong(my_Handle, GWL_EXSTYLE, WS_EX_APPWINDOW);
+
+	SetWindowPos(my_Handle, HWND_TOP, 0, 0, Mode.Width, Mode.Height, SWP_FRAMECHANGED);
+}
+
+LRESULT CALLBACK Window::Window_Procedure(HWND Handle, UINT Message, WPARAM wParam, LPARAM lParam)
+{
+	switch (Message)
+	{
+	case WM_CREATE:
+		{
+			LONG This = reinterpret_cast<LONG>(reinterpret_cast<CREATESTRUCT *>(lParam)->lpCreateParams);
+			SetWindowLongPtr(Handle, GWLP_USERDATA, This);
+			return 0;
+		}
+		break;
+	case WM_DESTROY:
+		PostQuitMessage(0);
+		return 0;
+		break;
+	default:
+		{
+			Window* Win = reinterpret_cast<Window *>(GetWindowLongPtr(Handle, GWLP_USERDATA));
+			if (Win)
+				return Win->Handle_Message(Handle, Message, wParam, lParam);
+		}
+		break;
+	}
+	return DefWindowProcW(Handle, Message, wParam, lParam);
+}
+
+#define Call_Listener(x)\
+	if (my_Listener) my_Listener->x
+
+LRESULT Window::Handle_Message(HWND Handle, UINT Message, WPARAM wParam, LPARAM lParam)
+{
+	bool IMM_Message = false;
+	LRESULT Result = my_IMM.Handle_Message(Handle, Message, wParam, lParam, IMM_Message);
+	if (IMM_Message)
+		return Result;
+
+	switch (Message)
+	{
+	case WM_SIZE:
+		Call_Listener(On_Resized(LOWORD(lParam), HIWORD(lParam)));
+		break;
+	case WM_CLOSE:
+		Call_Listener(On_Close());
+		break;
+	case WM_KEYDOWN:
+		Call_Listener(On_Key_Down(wParam));
+		break;
+	case WM_KEYUP:
+		Call_Listener(On_Key_Up(wParam));
+		break;
+	case WM_CHAR:
+		Call_Listener(On_Char(wParam));
+		break;
+	case WM_SETFOCUS:
+			my_IMM.Focus_Gained();
+		break;
+	case WM_KILLFOCUS:
+			my_IMM.Focus_Lost();
+		break;
+	case WM_LBUTTONDOWN:
+		Call_Listener(On_Mouse_Button_Down(Mouse_Button_Left));
+		break;
+	case WM_LBUTTONUP:
+		Call_Listener(On_Mouse_Button_Up(Mouse_Button_Left));
+		break;
+	case WM_RBUTTONDOWN:
+		Call_Listener(On_Mouse_Button_Down(Mouse_Button_Right));
+		break;
+	case WM_RBUTTONUP:
+		Call_Listener(On_Mouse_Button_Up(Mouse_Button_Right));
+		break;
+	default:
+		return DefWindowProcW(Handle, Message, wParam, lParam);
+		break;
+	}
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EXCLUDE/GLTSF/GLTSF.sln	Sun Aug 22 12:39:27 2010 -0700
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GLTSF", "GLTSF.vcxproj", "{790D58BA-E5F6-4286-A9C6-0DC28779789D}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{790D58BA-E5F6-4286-A9C6-0DC28779789D}.Debug|Win32.ActiveCfg = Debug|Win32
+		{790D58BA-E5F6-4286-A9C6-0DC28779789D}.Debug|Win32.Build.0 = Debug|Win32
+		{790D58BA-E5F6-4286-A9C6-0DC28779789D}.Release|Win32.ActiveCfg = Release|Win32
+		{790D58BA-E5F6-4286-A9C6-0DC28779789D}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EXCLUDE/GLTSF/GLTSF.vcproj	Sun Aug 22 12:39:27 2010 -0700
@@ -0,0 +1,231 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="GLTSF"
+	ProjectGUID="{FC8A9A48-6667-4BDE-8E9B-5859408AEE83}"
+	RootNamespace="GLTSF"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="196613"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)bin"
+			IntermediateDirectory="obj\$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)bin"
+			IntermediateDirectory="obj\$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\src\App.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\Main.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\TSF.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\Video_Mode.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\Window.cpp"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath=".\include\App.hpp"
+				>
+			</File>
+			<File
+				RelativePath=".\include\TSF.hpp"
+				>
+			</File>
+			<File
+				RelativePath=".\include\Video_Mode.hpp"
+				>
+			</File>
+			<File
+				RelativePath=".\include\Window.hpp"
+				>
+			</File>
+			<File
+				RelativePath=".\include\Window_Listener.hpp"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EXCLUDE/GLTSF/GLTSF.vcxproj	Sun Aug 22 12:39:27 2010 -0700
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{790D58BA-E5F6-4286-A9C6-0DC28779789D}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>GLTSF</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+    <OutDir>$(SolutionDir)bin\</OutDir>
+    <IntDir>obj\$(Configuration)\</IntDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+    <OutDir>$(SolutionDir)bin\</OutDir>
+    <IntDir>obj\$(Configuration)\</IntDir>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClInclude Include="include\App.hpp" />
+    <ClInclude Include="include\TSF.hpp" />
+    <ClInclude Include="include\Video_Mode.hpp" />
+    <ClInclude Include="include\Window.hpp" />
+    <ClInclude Include="include\Window_Listener.hpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="src\App.cpp" />
+    <ClCompile Include="src\Main.cpp" />
+    <ClCompile Include="src\TSF.cpp" />
+    <ClCompile Include="src\Video_Mode.cpp" />
+    <ClCompile Include="src\Window.cpp" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EXCLUDE/GLTSF/GLTSF.vcxproj.filters	Sun Aug 22 12:39:27 2010 -0700
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="include\App.hpp">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="include\Video_Mode.hpp">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="include\Window.hpp">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="include\Window_Listener.hpp">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="include\TSF.hpp">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="src\App.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Main.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Video_Mode.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Window.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="src\TSF.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+</Project>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EXCLUDE/GLTSF/GLTSF_vs2008.sln	Sun Aug 22 12:39:27 2010 -0700
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GLTSF", "GLTSF.vcproj", "{FC8A9A48-6667-4BDE-8E9B-5859408AEE83}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{FC8A9A48-6667-4BDE-8E9B-5859408AEE83}.Debug|Win32.ActiveCfg = Debug|Win32
+		{FC8A9A48-6667-4BDE-8E9B-5859408AEE83}.Debug|Win32.Build.0 = Debug|Win32
+		{FC8A9A48-6667-4BDE-8E9B-5859408AEE83}.Release|Win32.ActiveCfg = Release|Win32
+		{FC8A9A48-6667-4BDE-8E9B-5859408AEE83}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EXCLUDE/GLTSF/include/App.hpp	Sun Aug 22 12:39:27 2010 -0700
@@ -0,0 +1,36 @@
+#ifndef APP_HPP
+#define APP_HPP
+
+#include "Window.hpp"
+
+class App : public Window_Listener
+{
+public:
+	App();
+	virtual ~App();
+
+	void Initialize();
+	void Finalize();
+
+	void Run();
+
+	virtual void On_Close();
+	virtual void On_Key_Down(int Key);
+	virtual void On_Key_Up(int Key);
+	virtual void On_Char(unsigned int Char);
+	virtual void On_Resized(unsigned int Width, unsigned int Height);
+
+private:
+	void Update();
+	void Draw();
+
+	static const int Width = 800;
+	static const int Height = 600;
+	static const int Bits_Per_Pixel = 32;
+	static const bool Fullscreen = true;
+
+	Window my_Window;
+	bool my_Done;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EXCLUDE/GLTSF/include/TSF.hpp	Sun Aug 22 12:39:27 2010 -0700
@@ -0,0 +1,83 @@
+#ifndef TSF_HPP
+#define TSF_HPP
+
+#include <msctf.h>
+#include <atlbase.h>
+
+class TSF
+{
+public:
+	static void Initialize();
+	static void Finalize();
+
+private:
+	class TSF_Text_Store : public ITextStoreACP, public ITfContextOwnerCompositionSink
+	{
+	public:
+		//IUnknown
+		STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);
+		STDMETHODIMP_(ULONG) AddRef();
+		STDMETHODIMP_(ULONG) Release();
+
+		//ITextStoreACP
+		STDMETHODIMP AdviseSink(REFIID riid, IUnknown *punk, DWORD dwMask);
+		STDMETHODIMP UnadviseSink(IUnknown *punk);
+		STDMETHODIMP RequestLock(DWORD dwLockFlags, HRESULT *phrSession);
+		STDMETHODIMP GetStatus(TS_STATUS *pdcs);
+		STDMETHODIMP QueryInsert(LONG acpTestStart, LONG acpTestEnd, ULONG cch, LONG *pacpResultStart, LONG *pacpResultEnd);
+		STDMETHODIMP GetSelection(ULONG ulIndex, ULONG ulCount, TS_SELECTION_ACP *pSelection, ULONG *pcFetched);
+		STDMETHODIMP SetSelection(ULONG ulCount, const TS_SELECTION_ACP *pSelection);
+		STDMETHODIMP GetText(LONG acpStart, LONG acpEnd, WCHAR *pchPlain, ULONG cchPlainReq, ULONG *pcchPlainRet, TS_RUNINFO *prgRunInfo, ULONG cRunInfoReq, ULONG *pcRunInfoRet, LONG *pacpNext);
+		STDMETHODIMP SetText(DWORD dwFlags, LONG acpStart, LONG acpEnd, const WCHAR *pchText, ULONG cch, TS_TEXTCHANGE *pChange);
+		STDMETHODIMP GetFormattedText(LONG acpStart, LONG acpEnd, IDataObject **ppDataObject);
+		STDMETHODIMP GetEmbedded(LONG acpPos, REFGUID rguidService, REFIID riid, IUnknown **ppunk);
+		STDMETHODIMP QueryInsertEmbedded(const GUID *pguidService, const FORMATETC *pFormatEtc, BOOL *pfInsertable);
+		STDMETHODIMP InsertEmbedded(DWORD dwFlags, LONG acpStart, LONG acpEnd, IDataObject *pDataObject, TS_TEXTCHANGE *pChange);
+		STDMETHODIMP InsertTextAtSelection(DWORD dwFlags, const WCHAR *pchText, ULONG cch, LONG *pacpStart, LONG *pacpEnd, TS_TEXTCHANGE *pChange);
+		STDMETHODIMP InsertEmbeddedAtSelection(DWORD dwFlags, IDataObject *pDataObject, LONG *pacpStart, LONG *pacpEnd, TS_TEXTCHANGE *pChange);
+		STDMETHODIMP RequestSupportedAttrs(DWORD dwFlags, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs);
+		STDMETHODIMP RequestAttrsAtPosition(LONG acpPos, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs, DWORD dwFlags);
+		STDMETHODIMP RequestAttrsTransitioningAtPosition(LONG acpPos, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs, DWORD dwFlags);
+		STDMETHODIMP FindNextAttrTransition(LONG acpStart, LONG acpHalt, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs, DWORD dwFlags, LONG *pacpNext, BOOL *pfFound, LONG *plFoundOffset);
+		STDMETHODIMP RetrieveRequestedAttrs(ULONG ulCount, TS_ATTRVAL *paAttrVals, ULONG *pcFetched);
+		STDMETHODIMP GetEndACP(LONG *pacp);
+		STDMETHODIMP GetActiveView(TsViewCookie *pvcView);
+		STDMETHODIMP GetACPFromPoint(TsViewCookie vcView, const POINT *ptScreen, DWORD dwFlags, LONG *pacp);
+		STDMETHODIMP GetTextExt(TsViewCookie vcView, LONG acpStart, LONG acpEnd, RECT *prc, BOOL *pfClipped);
+		STDMETHODIMP GetScreenExt(TsViewCookie vcView, RECT *prc);
+		STDMETHODIMP GetWnd(TsViewCookie vcView, HWND *phwnd);
+
+		//ITfOwnerCompositionSink
+		STDMETHODIMP OnStartComposition(ITfCompositionView *pComposition, BOOL *pfOk);
+		STDMETHODIMP OnUpdateComposition(ITfCompositionView *pComposition, ITfRange *pRangeNew);
+		STDMETHODIMP OnEndComposition(ITfCompositionView *pComposition);
+
+		void Initialize();
+		void Finalize();
+
+		TSF_Text_Store();
+		~TSF_Text_Store();
+
+	private:
+		ULONG my_Reference_Count;
+		CComPtr<ITfDocumentMgr> my_Document_Manager;
+		CComPtr<ITfContext> my_Context;
+		DWORD my_Edit_Cookie;
+		CComPtr<ITextStoreACPSink> my_Sink;
+		DWORD my_Sink_Mask;
+		DWORD my_Lock;
+		DWORD my_Lock_Queued;
+		CComPtr<ITfCompositionView> my_Composition_View;
+		TS_SELECTION_ACP my_Composition_Selection;
+	};
+
+	TSF();
+
+	static bool COM_Initialized;
+
+	static CComPtr<ITfThreadMgr> Thread_Manager;
+	static TfClientId Client_Id;
+	static TSF_Text_Store *Text_Store;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EXCLUDE/GLTSF/include/Video_Mode.hpp	Sun Aug 22 12:39:27 2010 -0700
@@ -0,0 +1,30 @@
+#ifndef VIDEO_MODE_HPP
+#define VIDEO_MODE_HPP
+
+#include <cstddef>
+
+class Video_Mode
+{
+public:
+	Video_Mode();
+	Video_Mode(unsigned int The_Width, unsigned int The_Height, unsigned int The_Bits_Per_Pixel);
+
+	static Video_Mode Get_Desktop_Mode();
+
+	static std::size_t Get_Mode_Count();
+	static Video_Mode Get_Mode(std::size_t Index);
+
+	bool Is_Valid() const;
+
+	bool operator==(const Video_Mode &Mode) const;
+	bool operator!=(const Video_Mode &Mode) const;
+
+	unsigned int Width;
+	unsigned int Height;
+	unsigned int Bits_Per_Pixel;
+
+private:
+	static void Initialize_Modes();
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EXCLUDE/GLTSF/include/Window.hpp	Sun Aug 22 12:39:27 2010 -0700
@@ -0,0 +1,59 @@
+#ifndef WINDOW_HPP
+#define WINDOW_HPP
+
+#include <string>
+
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+
+#include "Video_Mode.hpp"
+#include "Window_Listener.hpp"
+#include "TSF.hpp"
+
+class Window
+{
+public:
+	Window();
+	~Window();
+
+	void Initialize(const std::wstring &Title, const Video_Mode &Mode, bool Fullscreen);
+	void Finalize();
+
+	void Set_Listener(Window_Listener *Listener);
+
+	void Show();
+	void Hide();
+
+	void Handle_Events();
+	void Display();
+
+	void Show_Cursor();
+	void Hide_Cursor();
+
+private:
+	static const wchar_t *Window_Class_Name;
+
+	void Register_Class();
+	void Unregister_Class();
+
+	void Create_Window(const std::wstring &Title, const Video_Mode &Mode, bool Fullscreen);
+	void Destroy_Window();
+
+	void Create_Context(const Video_Mode &Mode);
+	void Destroy_Context();
+
+	void Switch_To_Fullscreen(const Video_Mode &Mode);
+
+	LRESULT Handle_Message(HWND Handle, UINT Message, WPARAM wParam, LPARAM lParam);
+	static LRESULT CALLBACK Window_Procedure(HWND Handle, UINT Message, WPARAM wParam, LPARAM lParam);
+
+	HWND my_Handle;
+	Video_Mode my_Video_Mode;
+	bool my_Fullscreen;
+	HDC my_Device_Context;
+	HGLRC my_GL_Context;
+	bool my_Class_Registered;
+	Window_Listener *my_Listener;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EXCLUDE/GLTSF/include/Window_Listener.hpp	Sun Aug 22 12:39:27 2010 -0700
@@ -0,0 +1,14 @@
+#ifndef WINDOW_LISTENER_HPP
+#define WINDOW_LISTENER_HPP
+
+class Window_Listener
+{
+public:
+	virtual void On_Close(){}
+	virtual void On_Key_Down(int Key){}
+	virtual void On_Key_Up(int Key){}
+	virtual void On_Char(unsigned int Char){}
+	virtual void On_Resized(unsigned int Width, unsigned int Height){}
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EXCLUDE/GLTSF/src/App.cpp	Sun Aug 22 12:39:27 2010 -0700
@@ -0,0 +1,105 @@
+#include "App.hpp"
+#include "TSF.hpp"
+#include <GL/gl.h>
+#include <GL/glu.h>
+
+#pragma comment(lib, "glu32.lib")
+
+GLfloat Rotation = 0.0f;
+
+App::App() : my_Done(false)
+{
+	TSF::Initialize();
+}
+
+App::~App()
+{
+	Finalize();
+	TSF::Finalize();
+}
+
+void App::Initialize()
+{
+	Finalize();
+
+	my_Window.Initialize(L"GLTSF", Video_Mode(Width, Height, Bits_Per_Pixel), Fullscreen);
+	my_Window.Set_Listener(this);
+	my_Window.Show();
+	my_Window.Hide_Cursor();
+}
+
+void App::Finalize()
+{
+	my_Window.Finalize();
+}
+
+void App::Run()
+{
+	Initialize();
+	while (!my_Done)
+	{
+		my_Window.Handle_Events();
+
+		Update();
+		Draw();
+		my_Window.Display();
+	}
+}
+
+void App::On_Close()
+{
+	my_Done = true;
+	my_Window.Hide();
+}
+
+void App::On_Key_Down(int Key)
+{
+	switch (Key)
+	{
+	case VK_ESCAPE:
+		On_Close();
+		break;
+	}
+}
+
+void App::On_Key_Up(int Key)
+{
+
+}
+
+void App::On_Char(unsigned int Char)
+{
+	printf("Char: U+%04X\n", Char);
+}
+
+void App::On_Resized(unsigned int Width, unsigned int Height)
+{
+	glViewport(0, 0, Width, Height);
+	glMatrixMode(GL_PROJECTION);
+	glLoadIdentity();
+
+	glMatrixMode(GL_MODELVIEW);
+	glLoadIdentity();
+}
+
+void App::Update()
+{
+	Rotation += 0.2f;
+}
+
+void App::Draw()
+{
+	glClear(GL_COLOR_BUFFER_BIT);
+
+	glLoadIdentity();
+	glRotatef(Rotation, 0.0f, 0.0f, -1.0f);
+
+	glBegin(GL_TRIANGLES);
+		glColor3f(0.7f, 0.0f, 0.0f);
+		glVertex3f(0.0f, 0.5f, 0.0f);
+		glColor3f(0.0f, 0.7f, 0.0f);
+		glVertex3f(-0.5f, -0.5f, 0.0f);
+		glColor3f(0.0f, 0.0f, 0.7f);
+		glVertex3f(0.5f, -0.5f, 0.0f);
+	glEnd();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EXCLUDE/GLTSF/src/Main.cpp	Sun Aug 22 12:39:27 2010 -0700
@@ -0,0 +1,24 @@
+#include "App.hpp"
+#include <stdexcept>
+
+int main(int argc, char *argv[])
+{
+	int Result = EXIT_SUCCESS;
+	try
+	{
+		App theApp;
+		theApp.Run();
+	}
+	catch (const std::exception& e)
+	{
+		printf("Error: %s\n", e.what());
+		Result = EXIT_FAILURE;
+	}
+	catch (...)
+	{
+		printf("Unhandled exception\n");
+		Result = EXIT_FAILURE;
+	}
+	system("PAUSE");
+	return Result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EXCLUDE/GLTSF/src/TSF.cpp	Sun Aug 22 12:39:27 2010 -0700
@@ -0,0 +1,360 @@
+#include "TSF.hpp"
+#include <stdexcept>
+
+bool TSF::COM_Initialized = false;
+CComPtr<ITfThreadMgr> TSF::Thread_Manager;
+TfClientId TSF::Client_Id;
+TSF::TSF_Text_Store *TSF::Text_Store = NULL;
+
+void TSF::Initialize()
+{
+	if (!COM_Initialized)
+	{
+		HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+		if (S_OK != hr && S_FALSE != hr)
+			throw std::runtime_error("Failed to initialize COM");
+
+		COM_Initialized = true;
+	}
+	if (!Thread_Manager)
+	{
+		if (FAILED(CoCreateInstance(CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, IID_ITfThreadMgr, reinterpret_cast<void **>(&Thread_Manager))))
+			throw std::runtime_error("Failed to create ITfThreadMgr instance");
+
+		if (FAILED(Thread_Manager->Activate(&Client_Id)))
+			throw std::runtime_error("ITfThreadMgr::Activate failed");
+
+		Text_Store = new TSF_Text_Store;
+		Text_Store->Initialize();
+	}
+}
+
+void TSF::Finalize()
+{
+	if (Thread_Manager)
+	{
+		Thread_Manager->Deactivate();
+		Thread_Manager = NULL;
+	}
+	if (COM_Initialized)
+	{
+		CoUninitialize();
+		COM_Initialized = false;
+	}
+}
+
+STDMETHODIMP TSF::TSF_Text_Store::QueryInterface(REFIID riid, void **ppvObject)
+{
+	*ppvObject = NULL;
+	if (IID_IUnknown == riid || IID_ITextStoreACP == riid)
+		*ppvObject = static_cast<ITextStoreACP *>(this);
+	else if (IID_ITfContextOwnerCompositionSink == riid)
+		*ppvObject = static_cast<ITfContextOwnerCompositionSink *>(this);
+
+	if (*ppvObject)
+	{
+		AddRef();
+		return S_OK;
+	}
+	return E_NOINTERFACE;
+}
+
+STDMETHODIMP_(ULONG) TSF::TSF_Text_Store::AddRef()
+{
+	return ++my_Reference_Count;
+}
+
+STDMETHODIMP_(ULONG) TSF::TSF_Text_Store::Release()
+{
+	--my_Reference_Count;
+	if (0 != my_Reference_Count)
+		return my_Reference_Count;
+
+	delete this;
+	return 0;
+}
+
+#define CHECK_CONDITION(condition, retval, function, line)						\
+	if (!condition)																\
+	{																			\
+		printf("%s:%d: Condition failure: %s\n", function, line, #condition);	\
+	}
+
+#define ENSURE(condition, retval)	CHECK_CONDITION(condition, retval, __FUNCTION__, __LINE__)
+
+STDMETHODIMP TSF::TSF_Text_Store::AdviseSink(REFIID riid, IUnknown *punk, DWORD dwMask)
+{
+	ENSURE(punk && IID_ITextStoreACP == riid, E_INVALIDARG);
+
+	if (!my_Sink)
+	{
+		HRESULT hr = punk->QueryInterface(&my_Sink);
+		ENSURE(SUCCEEDED(hr) && my_Sink, E_UNEXPECTED);
+	}
+	else
+	{
+		CComPtr<IUnknown> Unknown_1, Unknown_2;
+		punk->QueryInterface(&Unknown_1);
+		my_Sink->QueryInterface(&Unknown_2);
+		if (Unknown_1 != Unknown_2)
+			return CONNECT_E_ADVISELIMIT;
+	}
+	my_Sink_Mask = dwMask;
+	return S_OK;
+}
+
+STDMETHODIMP TSF::TSF_Text_Store::UnadviseSink(IUnknown *punk)
+{
+	ENSURE(punk, E_INVALIDARG);
+	ENSURE(my_Sink, CONNECT_E_NOCONNECTION);
+
+	CComPtr<IUnknown> Unknown_1, Unknown_2;
+	punk->QueryInterface(&Unknown_1);
+	my_Sink->QueryInterface(&Unknown_2);
+
+	if (Unknown_1 != Unknown_2)
+		return CONNECT_E_NOCONNECTION;
+
+	my_Sink = NULL;
+	my_Sink_Mask = 0;
+	return S_OK;
+}
+
+STDMETHODIMP TSF::TSF_Text_Store::RequestLock(DWORD dwLockFlags, HRESULT *phrSession)
+{
+	ENSURE(my_Sink, E_FAIL);
+	ENSURE(phrSession, E_INVALIDARG);
+	if (my_Lock)
+	{
+		if (TS_LF_READ == (my_Lock & TS_LF_READWRITE)
+			&& TS_LF_READWRITE == (dwLockFlags & TS_LF_READWRITE)
+			&& !(dwLockFlags & TS_LF_SYNC))
+		{
+			*phrSession = TS_S_ASYNC;
+			my_Lock_Queued = dwLockFlags & (~TS_LF_SYNC);
+		}
+		else
+		{
+			*phrSession = TS_E_SYNCHRONOUS;
+			return E_FAIL;
+		}
+	}
+	else
+	{
+		my_Lock = dwLockFlags & (~TS_LF_SYNC);
+		*phrSession = my_Sink->OnLockGranted(my_Lock);
+		while (my_Lock_Queued)
+		{
+			my_Lock = my_Lock_Queued;
+			my_Lock_Queued = 0;
+			my_Sink->OnLockGranted(my_Lock);
+		}
+		my_Lock = 0;
+	}
+	return S_OK;
+}
+
+STDMETHODIMP TSF::TSF_Text_Store::GetStatus(TS_STATUS *pdcs)
+{
+	ENSURE(pdcs, E_INVALIDARG);
+	pdcs->dwDynamicFlags = 0;
+	pdcs->dwStaticFlags = TS_SS_NOHIDDENTEXT;
+	return S_OK;
+}
+
+STDMETHODIMP TSF::TSF_Text_Store::QueryInsert(LONG acpTestStart, LONG acpTestEnd, ULONG cch, LONG *pacpResultStart, LONG *pacpResultEnd)
+{
+	ENSURE(0 <= acpTestStart && acpTestStart <= acpTestEnd && pacpResultStart && pacpResultEnd, E_INVALIDARG);
+
+	*pacpResultStart = acpTestStart;
+	*pacpResultEnd = acpTestStart + cch;
+	return S_OK;
+}
+
+STDMETHODIMP TSF::TSF_Text_Store::GetSelection(ULONG ulIndex, ULONG ulCount, TS_SELECTION_ACP *pSelection, ULONG *pcFetched)
+{
+	ENSURE(TS_LF_READ == (my_Lock && TS_LF_READ), TS_E_NOLOCK);
+	ENSURE(ulCount && pSelection && pcFetched, E_INVALIDARG);
+
+	*pcFetched = 0;
+	ENSURE(TS_DEFAULT_SELECTION == ulIndex || 0 == ulIndex, TS_E_NOSELECTION);
+	if (my_Composition_View)
+	{
+		*pSelection = my_Composition_Selection;
+	}
+	else
+	{
+		//TODO
+	}
+	*pcFetched = 1;
+	return S_OK;
+}
+
+STDMETHODIMP TSF::TSF_Text_Store::SetSelection(ULONG ulCount, const TS_SELECTION_ACP *pSelection)
+{
+	return E_NOTIMPL;
+}
+
+STDMETHODIMP TSF::TSF_Text_Store::GetText(LONG acpStart, LONG acpEnd, WCHAR *pchPlain, ULONG cchPlainReq, ULONG *pcchPlainRet, TS_RUNINFO *prgRunInfo, ULONG cRunInfoReq, ULONG *pcRunInfoRet, LONG *pacpNext)
+{
+	ENSURE(TS_LF_READ == (my_Lock & TS_LF_READ), TS_E_NOLOCK);
+	ENSURE(pcchPlainRet && (pchPlain || prgRunInfo)
+		&& (!cchPlainReq == !pchPlain)
+		&& (!cRunInfoReq == !prgRunInfo), E_INVALIDARG);
+	ENSURE(0 <= acpStart && -1 <= acpEnd
+		&& (-1 == acpEnd || acpStart <= acpEnd), TS_E_INVALIDPOS);
+
+	*pcchPlainRet = 0;
+	if (pchPlain && cchPlainReq) *pchPlain = 0;
+	if (pcRunInfoRet) *pcRunInfoRet = 0;
+	//TODO
+	return S_OK;
+}
+
+STDMETHODIMP TSF::TSF_Text_Store::SetText(DWORD dwFlags, LONG acpStart, LONG acpEnd, const WCHAR *pchText, ULONG cch, TS_TEXTCHANGE *pChange)
+{
+	return E_NOTIMPL;
+}
+
+STDMETHODIMP TSF::TSF_Text_Store::GetFormattedText(LONG acpStart, LONG acpEnd, IDataObject **ppDataObject)
+{
+	//not needed
+	return E_NOTIMPL;
+}
+
+STDMETHODIMP TSF::TSF_Text_Store::GetEmbedded(LONG acpPos, REFGUID rguidService, REFIID riid, IUnknown **ppunk)
+{
+	//not needed
+	return E_NOTIMPL;
+}
+
+STDMETHODIMP TSF::TSF_Text_Store::QueryInsertEmbedded(const GUID *pguidService, const FORMATETC *pFormatEtc, BOOL *pfInsertable)
+{
+	if (!pfInsertable)
+		return E_INVALIDARG;
+
+	//Not supported
+	*pfInsertable = FALSE;
+	return E_NOTIMPL;
+}
+
+STDMETHODIMP TSF::TSF_Text_Store::InsertEmbedded(DWORD dwFlags, LONG acpStart, LONG acpEnd, IDataObject *pDataObject, TS_TEXTCHANGE *pChange)
+{
+	return E_NOTIMPL;
+}
+
+STDMETHODIMP TSF::TSF_Text_Store::InsertTextAtSelection(DWORD dwFlags, const WCHAR *pchText, ULONG cch, LONG *pacpStart, LONG *pacpEnd, TS_TEXTCHANGE *pChange)
+{
+	return E_NOTIMPL;
+}
+
+STDMETHODIMP TSF::TSF_Text_Store::InsertEmbeddedAtSelection(DWORD dwFlags, IDataObject *pDataObject, LONG *pacpStart, LONG *pacpEnd, TS_TEXTCHANGE *pChange)
+{
+	//not needed
+	return E_NOTIMPL;
+}
+
+STDMETHODIMP TSF::TSF_Text_Store::RequestSupportedAttrs(DWORD dwFlags, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs)
+{
+	//not needed
+	return E_NOTIMPL;
+}
+
+STDMETHODIMP TSF::TSF_Text_Store::RequestAttrsAtPosition(LONG acpPos, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs, DWORD dwFlags)
+{
+	//not needed
+	return E_NOTIMPL;
+}
+
+STDMETHODIMP TSF::TSF_Text_Store::RequestAttrsTransitioningAtPosition(LONG acpPos, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs, DWORD dwFlags)
+{
+	//not needed
+	return E_NOTIMPL;
+}
+
+STDMETHODIMP TSF::TSF_Text_Store::FindNextAttrTransition(LONG acpStart, LONG acpHalt, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs, DWORD dwFlags, LONG *pacpNext, BOOL *pfFound, LONG *plFoundOffset)
+{
+	//not needed
+	return E_NOTIMPL;
+}
+
+STDMETHODIMP TSF::TSF_Text_Store::RetrieveRequestedAttrs(ULONG ulCount, TS_ATTRVAL *paAttrVals, ULONG *pcFetched)
+{
+	//not needed
+	return E_NOTIMPL;
+}
+
+STDMETHODIMP TSF::TSF_Text_Store::GetEndACP(LONG *pacp)
+{
+	return E_NOTIMPL;
+}
+
+STDMETHODIMP TSF::TSF_Text_Store::GetActiveView(TsViewCookie *pvcView)
+{
+	return E_NOTIMPL;
+}
+
+STDMETHODIMP TSF::TSF_Text_Store::GetACPFromPoint(TsViewCookie vcView, const POINT *ptScreen, DWORD dwFlags, LONG *pacp)
+{
+	return E_NOTIMPL;
+}
+
+STDMETHODIMP TSF::TSF_Text_Store::GetTextExt(TsViewCookie vcView, LONG acpStart, LONG acpEnd, RECT *prc, BOOL *pfClipped)
+{
+	return E_NOTIMPL;
+}
+
+STDMETHODIMP TSF::TSF_Text_Store::GetScreenExt(TsViewCookie vcView, RECT *prc)
+{
+	return E_NOTIMPL;
+}
+
+STDMETHODIMP TSF::TSF_Text_Store::GetWnd(TsViewCookie vcView, HWND *phwnd)
+{
+	return E_NOTIMPL;
+}
+
+STDMETHODIMP TSF::TSF_Text_Store::OnStartComposition(ITfCompositionView *pComposition, BOOL *pfOk)
+{
+	return E_NOTIMPL;
+}
+
+STDMETHODIMP TSF::TSF_Text_Store::OnUpdateComposition(ITfCompositionView *pComposition, ITfRange *pRangeNew)
+{
+	return E_NOTIMPL;
+}
+
+STDMETHODIMP TSF::TSF_Text_Store::OnEndComposition(ITfCompositionView *pComposition)
+{
+	return E_NOTIMPL;
+}
+
+TSF::TSF_Text_Store::TSF_Text_Store() : my_Reference_Count(1),
+										my_Edit_Cookie(0),
+										my_Lock(0),
+										my_Lock_Queued(0)
+{
+
+}
+
+TSF::TSF_Text_Store::~TSF_Text_Store()
+{
+
+}
+
+void TSF::TSF_Text_Store::Initialize()
+{
+	if (FAILED(Thread_Manager->CreateDocumentMgr(&my_Document_Manager)))
+		throw std::runtime_error("Failed to create document manager");
+
+	if (FAILED(my_Document_Manager->CreateContext(Client_Id, 0, static_cast<ITextStoreACP *>(this), &my_Context, &my_Edit_Cookie)))
+		throw std::runtime_error("Failed to create document context");
+
+	if (FAILED(my_Document_Manager->Push(my_Context)))
+		throw std::runtime_error("Failed to push context");
+}
+
+void TSF::TSF_Text_Store::Finalize()
+{
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EXCLUDE/GLTSF/src/Video_Mode.cpp	Sun Aug 22 12:39:27 2010 -0700
@@ -0,0 +1,100 @@
+#include "Video_Mode.hpp"
+#include <vector>
+#include <algorithm>
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+
+namespace
+{
+
+	typedef std::vector<Video_Mode> Video_Mode_List;
+	Video_Mode_List Supported_Modes;
+
+	struct Compare_Modes
+	{
+		bool operator()(const Video_Mode &Mode_1, const Video_Mode &Mode_2) const
+		{
+			if (Mode_1.Bits_Per_Pixel > Mode_2.Bits_Per_Pixel)
+				return true;
+			else if (Mode_1.Bits_Per_Pixel < Mode_2.Bits_Per_Pixel)
+				return false;
+			else if (Mode_1.Width > Mode_2.Width)
+				return true;
+			else if (Mode_1.Width < Mode_2.Width)
+				return false;
+			else
+				return Mode_1.Height > Mode_2.Height;
+		}
+	};
+
+}
+
+Video_Mode::Video_Mode() : Width(0),
+						   Height(0),
+						   Bits_Per_Pixel(0)
+{
+
+}
+
+Video_Mode::Video_Mode(unsigned int The_Width, unsigned int The_Height, unsigned int The_Bits_Per_Pixel)
+	: Width(The_Width),
+	  Height(The_Height),
+	  Bits_Per_Pixel(The_Bits_Per_Pixel)
+{
+
+}
+
+Video_Mode Video_Mode::Get_Desktop_Mode()
+{
+	DEVMODE Device_Mode = {0};
+	Device_Mode.dmSize = sizeof(Device_Mode);
+	EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &Device_Mode);
+	return Video_Mode(Device_Mode.dmPelsWidth, Device_Mode.dmPelsHeight, Device_Mode.dmBitsPerPel);
+}
+
+std::size_t Video_Mode::Get_Mode_Count()
+{
+	Initialize_Modes();
+	return Supported_Modes.size();
+}
+
+Video_Mode Video_Mode::Get_Mode(std::size_t Index)
+{
+	Initialize_Modes();
+	return Supported_Modes[Index];
+}
+
+bool Video_Mode::Is_Valid() const
+{
+	Initialize_Modes();
+	return Supported_Modes.end() != std::find(Supported_Modes.begin(), Supported_Modes.end(), *this);
+}
+
+bool Video_Mode::operator==(const Video_Mode &Mode) const
+{
+	return (Width == Mode.Width
+		&&  Height == Mode.Height
+		&&  Bits_Per_Pixel == Mode.Bits_Per_Pixel);
+}
+
+bool Video_Mode::operator!=(const Video_Mode &Mode) const
+{
+	return !(*this == Mode);
+}
+
+void Video_Mode::Initialize_Modes()
+{
+	static bool Initialized = false;
+	if (!Initialized)
+	{
+		DEVMODE Device_Mode = {0};
+		Device_Mode.dmSize = sizeof(Device_Mode);
+		for (std::size_t i = 0; 0 != EnumDisplaySettings(NULL, i, &Device_Mode); ++i)
+		{
+			Video_Mode Mode(Device_Mode.dmPelsWidth, Device_Mode.dmPelsHeight, Device_Mode.dmBitsPerPel);
+			if (Supported_Modes.end() == std::find(Supported_Modes.begin(), Supported_Modes.end(), Mode))
+				Supported_Modes.push_back(Mode);
+		}
+		std::sort(Supported_Modes.begin(), Supported_Modes.end(), Compare_Modes());
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EXCLUDE/GLTSF/src/Window.cpp	Sun Aug 22 12:39:27 2010 -0700
@@ -0,0 +1,281 @@
+#include "Window.hpp"
+#include <gl/GL.h>
+
+#pragma comment(lib, "opengl32.lib")
+
+const wchar_t *Window::Window_Class_Name = L"GLTSF";
+
+Window::Window() : my_Handle(0),
+				   my_Device_Context(0),
+				   my_GL_Context(0),
+				   my_Class_Registered(false),
+				   my_Listener(0)
+{
+
+}
+
+Window::~Window()
+{
+	Finalize();
+	Show_Cursor();
+}
+
+void Window::Initialize(const std::wstring &Title, const Video_Mode &Mode, bool Fullscreen)
+{
+	Finalize();
+
+	my_Video_Mode = Mode;
+	if (!my_Video_Mode.Is_Valid())
+		throw std::runtime_error("Invalid video mode");
+
+	my_Fullscreen = Fullscreen;
+	Register_Class();
+	Create_Window(Title, Mode, Fullscreen);
+}
+
+void Window::Finalize()
+{
+	Destroy_Window();
+	Unregister_Class();
+}
+
+void Window::Set_Listener(Window_Listener *Listener)
+{
+	my_Listener = Listener;
+}
+
+void Window::Register_Class()
+{
+	WNDCLASSEXW Window_Class = {0};
+	Window_Class.cbSize = sizeof(Window_Class);
+	Window_Class.style = 0;
+	Window_Class.lpfnWndProc = &Window::Window_Procedure;
+	Window_Class.cbClsExtra = 0;
+	Window_Class.cbWndExtra = 0;
+	Window_Class.hInstance = GetModuleHandle(NULL);
+	Window_Class.hIcon = NULL;
+	Window_Class.hCursor = NULL;
+	Window_Class.hbrBackground = NULL;
+	Window_Class.lpszMenuName = NULL;
+	Window_Class.lpszClassName = Window_Class_Name;
+	Window_Class.hIconSm = NULL;
+	if (0 == RegisterClassExW(&Window_Class))
+		throw std::runtime_error("Failed to register window class");
+
+	my_Class_Registered = true;
+}
+
+void Window::Unregister_Class()
+{
+	if (my_Class_Registered)
+	{
+		if (0 == UnregisterClassW(Window_Class_Name, GetModuleHandle(NULL)))
+			printf("Warning: Failed to unregister window class\n");
+
+		my_Class_Registered = false;
+	}
+}
+
+void Window::Create_Window(const std::wstring &Title, const Video_Mode &Mode, bool Fullscreen)
+{
+	HDC Screen_DC = GetDC(NULL);
+	int Left = (GetDeviceCaps(Screen_DC, HORZRES) - my_Video_Mode.Width) / 2;
+	int Top = (GetDeviceCaps(Screen_DC, VERTRES) - my_Video_Mode.Height) / 2;
+	int Width = my_Video_Mode.Width;
+	int Height = my_Video_Mode.Height;
+	ReleaseDC(NULL, Screen_DC);
+
+	DWORD Style = WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;
+	if (!my_Fullscreen)
+	{
+		RECT Rect = {0, 0, Width, Height};
+		AdjustWindowRect(&Rect, Style, false);
+		Width = Rect.right - Rect.left;
+		Height = Rect.bottom - Rect.top;
+	}
+	my_Handle = CreateWindowW(Window_Class_Name, Title.c_str(), Style, Left, Top, Width, Height, NULL, NULL, GetModuleHandle(NULL), this);
+	if (!my_Handle)
+		throw std::runtime_error("Failed to create window");
+
+	if (Fullscreen)
+		Switch_To_Fullscreen(Mode);
+
+	Create_Context(Mode);
+
+	RECT Rect = {0};
+	GetClientRect(my_Handle, &Rect);
+	//TODO: ...
+}
+
+void Window::Destroy_Window()
+{
+	Destroy_Context();
+	if (my_Handle)
+	{
+		DestroyWindow(my_Handle);
+		my_Handle = 0;
+
+		if (my_Fullscreen)
+			ChangeDisplaySettings(NULL, 0);
+	}
+}
+
+void Window::Create_Context(const Video_Mode &Mode)
+{
+	my_Device_Context = GetDC(my_Handle);
+	if (!my_Device_Context)
+		throw std::runtime_error("Failed to get device context");
+
+	PIXELFORMATDESCRIPTOR Pixel_Descriptor = {0};
+	Pixel_Descriptor.nSize = sizeof(Pixel_Descriptor);
+	Pixel_Descriptor.nVersion = 1;
+	Pixel_Descriptor.iLayerType = PFD_MAIN_PLANE;
+	Pixel_Descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
+	Pixel_Descriptor.iPixelType = PFD_TYPE_RGBA;
+	Pixel_Descriptor.cColorBits = static_cast<BYTE>(Mode.Bits_Per_Pixel);
+	Pixel_Descriptor.cDepthBits = 24;
+	Pixel_Descriptor.cStencilBits = 8;
+	Pixel_Descriptor.cAlphaBits = Mode.Bits_Per_Pixel == 32 ? 8 : 0;
+
+	int Best_Format = ChoosePixelFormat(my_Device_Context, &Pixel_Descriptor);
+	if (0 == Best_Format)
+		throw std::runtime_error("Failed to find suitable pixel format");
+
+	PIXELFORMATDESCRIPTOR Actual_Format = {0};
+	Actual_Format.nSize = sizeof(Actual_Format);
+	Actual_Format.nVersion = 1;
+	DescribePixelFormat(my_Device_Context, Best_Format, sizeof(Actual_Format), &Actual_Format);
+	if (!SetPixelFormat(my_Device_Context, Best_Format, &Actual_Format))
+		throw std::runtime_error("Failed to set device pixel format");
+
+	my_GL_Context = wglCreateContext(my_Device_Context);
+	if (!my_GL_Context)
+		throw std::runtime_error("Failed to create OpenGL context");
+
+	wglMakeCurrent(my_Device_Context, my_GL_Context);
+}
+
+void Window::Destroy_Context()
+{
+	if (my_GL_Context)
+	{
+		wglDeleteContext(my_GL_Context);
+		my_GL_Context = 0;
+	}
+	if (my_Device_Context)
+	{
+		ReleaseDC(my_Handle, my_Device_Context);
+		my_Device_Context = 0;
+	}
+}
+
+void Window::Switch_To_Fullscreen(const Video_Mode &Mode)
+{
+	DEVMODE Device_Mode = {0};
+	Device_Mode.dmSize = sizeof(Device_Mode);
+	Device_Mode.dmPelsWidth = Mode.Width;
+	Device_Mode.dmPelsHeight = Mode.Height;
+	Device_Mode.dmBitsPerPel = Mode.Bits_Per_Pixel;
+	Device_Mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
+
+	if (DISP_CHANGE_SUCCESSFUL != ChangeDisplaySettings(&Device_Mode, CDS_FULLSCREEN))
+		throw std::runtime_error("Failed to change to fullscreen mode");
+
+	SetWindowLong(my_Handle, GWL_STYLE, WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
+	SetWindowLong(my_Handle, GWL_EXSTYLE, WS_EX_APPWINDOW);
+
+	SetWindowPos(my_Handle, HWND_TOP, 0, 0, Mode.Width, Mode.Height, SWP_FRAMECHANGED);
+}
+
+LRESULT CALLBACK Window::Window_Procedure(HWND Handle, UINT Message, WPARAM wParam, LPARAM lParam)
+{
+	switch (Message)
+	{
+	case WM_CREATE:
+		{
+			LONG This = reinterpret_cast<LONG>(reinterpret_cast<CREATESTRUCT *>(lParam)->lpCreateParams);
+			SetWindowLongPtr(Handle, GWLP_USERDATA, This);
+			return 0;
+		}
+		break;
+	case WM_DESTROY:
+		PostQuitMessage(0);
+		return 0;
+		break;
+	default:
+		{
+			Window* Win = reinterpret_cast<Window *>(GetWindowLongPtr(Handle, GWLP_USERDATA));
+			if (Win)
+				return Win->Handle_Message(Handle, Message, wParam, lParam);
+		}
+		break;
+	}
+	return DefWindowProcW(Handle, Message, wParam, lParam);
+}
+
+#define Call_Listener(x)\
+	if (my_Listener) my_Listener->x
+
+LRESULT Window::Handle_Message(HWND Handle, UINT Message, WPARAM wParam, LPARAM lParam)
+{
+	switch (Message)
+	{
+	case WM_SIZE:
+		Call_Listener(On_Resized(LOWORD(lParam), HIWORD(lParam)));
+		break;
+	case WM_CLOSE:
+		Call_Listener(On_Close());
+		break;
+	case WM_KEYDOWN:
+		Call_Listener(On_Key_Down(wParam));
+		break;
+	case WM_KEYUP:
+		Call_Listener(On_Key_Up(wParam));
+		break;
+	case WM_CHAR:
+		Call_Listener(On_Char(wParam));
+		break;
+	default:
+		return DefWindowProcW(Handle, Message, wParam, lParam);
+		break;
+	}
+	return 0;
+}
+
+void Window::Show()
+{
+	if (my_Handle)
+		ShowWindow(my_Handle, SW_SHOW);
+}
+
+void Window::Hide()
+{
+	if (my_Handle)
+		ShowWindow(my_Handle, SW_HIDE);
+}
+
+void Window::Handle_Events()
+{
+	MSG Message = {0};
+	while (PeekMessageW(&Message, NULL, 0, 0, PM_REMOVE))
+	{
+		TranslateMessage(&Message);
+		DispatchMessageW(&Message);
+	}
+}
+
+void Window::Display()
+{
+	if (my_Device_Context && my_GL_Context)
+		SwapBuffers(my_Device_Context);
+}
+
+void Window::Show_Cursor()
+{
+	ShowCursor(TRUE);
+}
+
+void Window::Hide_Cursor()
+{
+	ShowCursor(FALSE);
+}
--- a/include/SDL_stdinc.h	Sun Aug 22 12:35:34 2010 -0700
+++ b/include/SDL_stdinc.h	Sun Aug 22 12:39:27 2010 -0700
@@ -472,6 +472,19 @@
 extern DECLSPEC size_t SDLCALL SDL_wcslen(const wchar_t * string);
 #endif
 
+#ifdef HAVE_WCSLCPY
+#define SDL_wcslcpy      wcslcpy
+#else
+extern DECLSPEC size_t SDLCALL SDL_wcslcpy(wchar_t *dst, const wchar_t *src, size_t maxlen);
+#endif
+
+#ifdef HAVE_WCSLCAT
+#define SDL_wcslcat      wcslcat
+#else
+extern DECLSPEC size_t SDLCALL SDL_wcslcat(wchar_t *dst, const wchar_t *src, size_t maxlen);
+#endif
+
+
 #ifdef HAVE_STRLCPY
 #define SDL_strlcpy     strlcpy
 #else
@@ -479,6 +492,9 @@
                                            size_t maxlen);
 #endif
 
+extern DECLSPEC size_t SDLCALL SDL_utf8strlcpy(char *dst, const char *src,
+                                            size_t dst_bytes);
+
 #ifdef HAVE_STRLCAT
 #define SDL_strlcat    strlcat
 #else
--- a/src/events/SDL_keyboard.c	Sun Aug 22 12:35:34 2010 -0700
+++ b/src/events/SDL_keyboard.c	Sun Aug 22 12:39:27 2010 -0700
@@ -778,7 +778,7 @@
         SDL_Event event;
         event.text.type = SDL_TEXTINPUT;
         event.text.windowID = keyboard->focus ? keyboard->focus->id : 0;
-        SDL_strlcpy(event.text.text, text, SDL_arraysize(event.text.text));
+        SDL_utf8strlcpy(event.text.text, text, SDL_arraysize(event.text.text));
         event.text.windowID = keyboard->focus ? keyboard->focus->id : 0;
         posted = (SDL_PushEvent(&event) > 0);
     }
@@ -799,7 +799,7 @@
         event.edit.windowID = keyboard->focus ? keyboard->focus->id : 0;
         event.edit.start = start;
         event.edit.length = length;
-        SDL_strlcpy(event.edit.text, text, SDL_arraysize(event.edit.text));
+        SDL_utf8strlcpy(event.edit.text, text, SDL_arraysize(event.edit.text));
         posted = (SDL_PushEvent(&event) > 0);
     }
     return (posted);
--- a/src/haptic/nds/SDL_syshaptic.c	Sun Aug 22 12:35:34 2010 -0700
+++ b/src/haptic/nds/SDL_syshaptic.c	Sun Aug 22 12:39:27 2010 -0700
@@ -43,35 +43,35 @@
 } NDS_HapticData;
 
 
-
void
-NDS_EZF_OpenNorWrite() 
+void
+NDS_EZF_OpenNorWrite() 
 {
-    
GBA_BUS[0x0FF0000] = 0xD200;
-    
GBA_BUS[0x0000000] = 0x1500;
-    
GBA_BUS[0x0010000] = 0xD200;
-    
GBA_BUS[0x0020000] = 0x1500;
-    
GBA_BUS[0x0E20000] = 0x1500;
-    
GBA_BUS[0x0FE0000] = 0x1500;
-
} 


void
+    GBA_BUS[0x0FF0000] = 0xD200;
+    GBA_BUS[0x0000000] = 0x1500;
+    GBA_BUS[0x0010000] = 0xD200;
+    GBA_BUS[0x0020000] = 0x1500;
+    GBA_BUS[0x0E20000] = 0x1500;
+    GBA_BUS[0x0FE0000] = 0x1500;
+} 

void
 
-NDS_EZF_CloseNorWrite() 
+NDS_EZF_CloseNorWrite() 
 {
-    
GBA_BUS[0x0FF0000] = 0xD200;
-    
GBA_BUS[0x0000000] = 0x1500;
-    
GBA_BUS[0x0010000] = 0xD200;
-    
GBA_BUS[0x0020000] = 0x1500;
-    
GBA_BUS[0x0E20000] = 0xD200;
-    
GBA_BUS[0x0FE0000] = 0x1500;
-
}
+    GBA_BUS[0x0FF0000] = 0xD200;
+    GBA_BUS[0x0000000] = 0x1500;
+    GBA_BUS[0x0010000] = 0xD200;
+    GBA_BUS[0x0020000] = 0x1500;
+    GBA_BUS[0x0E20000] = 0xD200;
+    GBA_BUS[0x0FE0000] = 0x1500;
+}
 
 void
 NDS_EZF_ChipReset()
 {
-    
GBA_BUS[0x0000] = 0x00F0;
-    
GBA_BUS[0x1000] = 0x00F0;
-} 
uint32 NDS_EZF_IsPresent() 
+    GBA_BUS[0x0000] = 0x00F0;
+    GBA_BUS[0x1000] = 0x00F0;
+} uint32 NDS_EZF_IsPresent() 
 {
-    
vuint16 id1, id2;
+    vuint16 id1, id2;
 
     NDS_EZF_OpenNorWrite();
 
@@ -81,35 +81,35 @@
     GBA_BUS[0x1555] = 0x00AA;
     GBA_BUS[0x12AA] = 0x0055;
     GBA_BUS[0x1555] = 0x0090;
-    
id1 = GBA_BUS[0x0001];
-    
id2 = GBA_BUS[0x1001];
-    
if ((id1 != 0x227E) || (id2 != 0x227E)) {
+    id1 = GBA_BUS[0x0001];
+    id2 = GBA_BUS[0x1001];
+    if ((id1 != 0x227E) || (id2 != 0x227E)) {
         NDS_EZF_CloseNorWrite();
-        
return 0;
+        return 0;
     }
-    

id1 = GBA_BUS[0x000E];
-    
id2 = GBA_BUS[0x100E];
+    id1 = GBA_BUS[0x000E];
+    id2 = GBA_BUS[0x100E];
 
     NDS_EZF_CloseNorWrite();
-    
if (id1 == 0x2218 && id2 == 0x2218) {
-        
return 1;
+    if (id1 == 0x2218 && id2 == 0x2218) {
+        return 1;
     }
-    
return 0;
-
}
-
void
-NDS_EZF_SetShake(u8 pos) 
+    return 0;
+}
+void
+NDS_EZF_SetShake(u8 pos) 
 {
     u16 data = ((pos % 3) | 0x00F0);
-    
GBA_BUS[0x0FF0000] = 0xD200;
-    
GBA_BUS[0x0000000] = 0x1500;
-    
GBA_BUS[0x0010000] = 0xD200;
-    
GBA_BUS[0x0020000] = 0x1500;
-    
GBA_BUS[0x0F10000] = data;
-    
GBA_BUS[0x0FE0000] = 0x1500;
+    GBA_BUS[0x0FF0000] = 0xD200;
+    GBA_BUS[0x0000000] = 0x1500;
+    GBA_BUS[0x0010000] = 0xD200;
+    GBA_BUS[0x0020000] = 0x1500;
+    GBA_BUS[0x0F10000] = data;
+    GBA_BUS[0x0FE0000] = 0x1500;
 
     GBA_BUS[0] = 0x0000;        /* write any value for vibration. */
     GBA_BUS[0] = 0x0002;
-
}
+}
 
 static int
 SDL_SYS_LogicError(void)
--- a/src/joystick/nds/SDL_sysjoystick.c	Sun Aug 22 12:35:34 2010 -0700
+++ b/src/joystick/nds/SDL_sysjoystick.c	Sun Aug 22 12:39:27 2010 -0700
@@ -45,7 +45,7 @@
 SDL_SYS_JoystickInit(void)
 {
     SDL_numjoysticks = 1;
-    
return (1);
+    return (1);
 }
 
 /* Function to get the device-dependent name of a joystick */
@@ -73,7 +73,7 @@
     return 0;
 }
 
-
+
 /* Function to update the state of a joystick - called as a device poll.
  * This function shouldn't update the joystick structure directly,
  * but instead should call SDL_PrivateJoystick*() to deliver events
@@ -84,8 +84,8 @@
 {
     u32 keysd, keysu;
     int magnitude = 16384;
-    
-        /*scanKeys(); - this is done in PumpEvents, because touch uses it too */ 
+    
+        /*scanKeys(); - this is done in PumpEvents, because touch uses it too */ 
         keysd = keysDown();
     keysu = keysUp();
 
@@ -101,61 +101,61 @@
     if ((keysd & KEY_RIGHT)) {
         SDL_PrivateJoystickAxis(joystick, 0, magnitude);
     }
-    
if ((keysu & (KEY_UP | KEY_DOWN))) {
+    if ((keysu & (KEY_UP | KEY_DOWN))) {
         SDL_PrivateJoystickAxis(joystick, 1, 0);
     }
-    
if ((keysu & (KEY_LEFT | KEY_RIGHT))) {
+    if ((keysu & (KEY_LEFT | KEY_RIGHT))) {
         SDL_PrivateJoystickAxis(joystick, 0, 0);
     }
-    
if ((keysd & KEY_A)) {
+    if ((keysd & KEY_A)) {
         SDL_PrivateJoystickButton(joystick, 0, SDL_PRESSED);
     }
-    
if ((keysd & KEY_B)) {
+    if ((keysd & KEY_B)) {
         SDL_PrivateJoystickButton(joystick, 1, SDL_PRESSED);
     }
-    
if ((keysd & KEY_X)) {
+    if ((keysd & KEY_X)) {
         SDL_PrivateJoystickButton(joystick, 2, SDL_PRESSED);
     }
-    
if ((keysd & KEY_Y)) {
+    if ((keysd & KEY_Y)) {
         SDL_PrivateJoystickButton(joystick, 3, SDL_PRESSED);
     }
-    
if ((keysd & KEY_L)) {
+    if ((keysd & KEY_L)) {
         SDL_PrivateJoystickButton(joystick, 4, SDL_PRESSED);
     }
-    
if ((keysd & KEY_R)) {
+    if ((keysd & KEY_R)) {
         SDL_PrivateJoystickButton(joystick, 5, SDL_PRESSED);
     }
-    
if ((keysd & KEY_SELECT)) {
+    if ((keysd & KEY_SELECT)) {
         SDL_PrivateJoystickButton(joystick, 6, SDL_PRESSED);
     }
-    
if ((keysd & KEY_START)) {
+    if ((keysd & KEY_START)) {
         SDL_PrivateJoystickButton(joystick, 7, SDL_PRESSED);
     }
-    
if ((keysu & KEY_A)) {
+    if ((keysu & KEY_A)) {
         SDL_PrivateJoystickButton(joystick, 0, SDL_RELEASED);
     }
-    
if ((keysu & KEY_B)) {
+    if ((keysu & KEY_B)) {
         SDL_PrivateJoystickButton(joystick, 1, SDL_RELEASED);
     }
-    
if ((keysu & KEY_X)) {
+    if ((keysu & KEY_X)) {
         SDL_PrivateJoystickButton(joystick, 2, SDL_RELEASED);
     }
-    
if ((keysu & KEY_Y)) {
+    if ((keysu & KEY_Y)) {
         SDL_PrivateJoystickButton(joystick, 3, SDL_RELEASED);
     }
-    
if ((keysu & KEY_L)) {
+    if ((keysu & KEY_L)) {
         SDL_PrivateJoystickButton(joystick, 4, SDL_RELEASED);
     }
-    
if ((keysu & KEY_R)) {
+    if ((keysu & KEY_R)) {
         SDL_PrivateJoystickButton(joystick, 5, SDL_RELEASED);
     }
-    
if ((keysu & KEY_SELECT)) {
+    if ((keysu & KEY_SELECT)) {
         SDL_PrivateJoystickButton(joystick, 6, SDL_RELEASED);
     }
-    
if ((keysu & KEY_START)) {
+    if ((keysu & KEY_START)) {
         SDL_PrivateJoystickButton(joystick, 7, SDL_RELEASED);
     }
-
}
+}
 
 /* Function to close a joystick after use */
 void
--- a/src/stdlib/SDL_string.c	Sun Aug 22 12:35:34 2010 -0700
+++ b/src/stdlib/SDL_string.c	Sun Aug 22 12:39:27 2010 -0700
@@ -29,6 +29,21 @@
 #define SDL_isupperhex(X)   (((X) >= 'A') && ((X) <= 'F'))
 #define SDL_islowerhex(X)   (((X) >= 'a') && ((X) <= 'f'))
 
+#define UTF8_IsLeadByte(c) ((c) >= 0xC0 && (c) <= 0xF4)
+#define UTF8_IsTrailingByte(c) ((c) >= 0x80 && (c) <= 0xBF)
+
+int UTF8_TrailingBytes(unsigned char c)
+{
+    if (c >= 0xC0 && c<= 0xDF)
+        return 1;
+    else if (c >= 0xE0 && c <= 0xEF)
+        return 2;
+    else if (c >= 0xF0 && c <= 0xF4)
+        return 3;
+    else
+        return 0;
+}
+
 #if !defined(HAVE_SSCANF) || !defined(HAVE_STRTOL)
 static size_t
 SDL_ScanLong(const char *text, int radix, long *valuep)
@@ -348,6 +363,33 @@
 }
 #endif
 
+#ifndef HAVE_WCSLCPY
+size_t
+SDL_wcslcpy(wchar_t *dst, const wchar_t *src, size_t maxlen)
+{
+    size_t srclen = SDL_wcslen(src);
+    if (maxlen > 0) {
+        size_t len = SDL_min(srclen, maxlen - 1);
+        SDL_memcpy(dst, src, len * sizeof(wchar_t));
+        dst[len] = '\0';
+    }
+    return srclen;
+}
+#endif
+
+#ifndef HAVE_WCSLCAT
+size_t
+SDL_wcslcat(wchar_t *dst, const wchar_t *src, size_t maxlen)
+{
+    size_t dstlen = SDL_wcslen(dst);
+    size_t srclen = SDL_wcslen(src);
+    if (dstlen < maxlen) {
+        SDL_wcslcpy(dst + dstlen, src, maxlen - dstlen);
+    }
+    return dstlen + srclen;
+}
+#endif
+
 #ifndef HAVE_STRLCPY
 size_t
 SDL_strlcpy(char *dst, const char *src, size_t maxlen)
@@ -362,6 +404,38 @@
 }
 #endif
 
+size_t SDL_utf8strlcpy(char *dst, const char *src, size_t dst_bytes)
+{
+    size_t src_bytes = SDL_strlen(src);
+    size_t bytes = SDL_min(src_bytes, dst_bytes - 1);
+    int i = 0;
+    char trailing_bytes = 0;
+    if (bytes)
+    {
+        unsigned char c = (unsigned char)src[bytes - 1];
+        if (UTF8_IsLeadByte(c))
+            --bytes;
+        else if (UTF8_IsTrailingByte(c))
+        {
+            for (i = bytes - 1; i != 0; --i)
+            {
+                c = (unsigned char)src[i];
+                trailing_bytes = UTF8_TrailingBytes(c);
+                if (trailing_bytes)
+                {
+                    if (bytes - i != trailing_bytes + 1)
+                        bytes = i;
+
+                    break;
+                }
+            }
+        }
+        SDL_memcpy(dst, src, bytes);
+    }
+    dst[bytes] = '\0';
+    return bytes;
+}
+
 #ifndef HAVE_STRLCAT
 size_t
 SDL_strlcat(char *dst, const char *src, size_t maxlen)
--- a/src/video/win32/SDL_win32events.c	Sun Aug 22 12:35:34 2010 -0700
+++ b/src/video/win32/SDL_win32events.c	Sun Aug 22 12:39:27 2010 -0700
@@ -139,6 +139,8 @@
     }
 
 #endif
+    if (IME_HandleMessage(hwnd, msg, wParam, &lParam, data->videodata))
+        return 0;
 
     switch (msg) {
 
@@ -605,7 +607,7 @@
     class.hbrBackground = NULL;
     class.hInstance = SDL_Instance;
     class.style = SDL_Appstyle;
-    class.lpfnWndProc = DefWindowProc;
+    class.lpfnWndProc = WIN_WindowProc;
     class.cbWndExtra = 0;
     class.cbClsExtra = 0;
     if (!RegisterClass(&class)) {
--- a/src/video/win32/SDL_win32keyboard.c	Sun Aug 22 12:35:34 2010 -0700
+++ b/src/video/win32/SDL_win32keyboard.c	Sun Aug 22 12:39:27 2010 -0700
@@ -26,6 +26,14 @@
 #include "../../events/SDL_keyboard_c.h"
 #include "../../events/scancodes_win32.h"
 
+#include <imm.h>
+#include <oleauto.h>
+
+static void IME_Init(SDL_VideoData *videodata, HWND hwnd);
+static void IME_Enable(SDL_VideoData *videodata, HWND hwnd);
+static void IME_Disable(SDL_VideoData *videodata, HWND hwnd);
+static void IME_Quit(SDL_VideoData *videodata);
+
 #ifndef MAPVK_VK_TO_VSC
 #define MAPVK_VK_TO_VSC     0
 #endif
@@ -81,6 +89,34 @@
 
     data->key_layout = win32_scancode_table;
 
+    data->ime_com_initialized = SDL_FALSE;
+    data->ime_threadmgr = 0;
+    data->ime_initialized = SDL_FALSE;
+    data->ime_enabled = SDL_FALSE;
+    data->ime_available = SDL_FALSE;
+    data->ime_hwnd_main = 0;
+    data->ime_hwnd_current = 0;
+    data->ime_himc = 0;
+    data->ime_composition[0] = 0;
+    data->ime_readingstring[0] = 0;
+    data->ime_cursor = 0;
+    data->ime_hkl = 0;
+    data->ime_himm32 = 0;
+    data->GetReadingString = 0;
+    data->ShowReadingWindow = 0;
+    data->ImmLockIMC = 0;
+    data->ImmUnlockIMC = 0;
+    data->ImmLockIMCC = 0;
+    data->ImmUnlockIMCC = 0;
+    data->ime_uiless = SDL_FALSE;
+    data->ime_threadmgrex = 0;
+    data->ime_uielemsinkcookie = TF_INVALID_COOKIE;
+    data->ime_alpnsinkcookie = TF_INVALID_COOKIE;
+    data->ime_openmodesinkcookie = TF_INVALID_COOKIE;
+    data->ime_convmodesinkcookie = TF_INVALID_COOKIE;
+    data->ime_uielemsink = 0;
+    data->ime_ippasink = 0;
+
     WIN_UpdateKeymap();
 
     SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu");
@@ -119,6 +155,851 @@
 void
 WIN_QuitKeyboard(_THIS)
 {
+    IME_Quit((SDL_VideoData *)_this->driverdata);
+}
+
+void
+WIN_StartTextInput(_THIS)
+{
+    SDL_Window *window = SDL_GetKeyboardFocus();
+    if (window) {
+        HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
+        SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
+        IME_Init(videodata, hwnd);
+        IME_Enable(videodata, hwnd);
+    }
+}
+
+void
+WIN_StopTextInput(_THIS)
+{
+    SDL_Window *window = SDL_GetKeyboardFocus();
+    if (window) {
+        HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
+        SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
+        IME_Init(videodata, hwnd);
+        IME_Disable(videodata, hwnd);
+    }
+}
+
+void
+WIN_SetTextInputRect(_THIS, SDL_Rect *rect)
+{
+
+}
+
+#define LANG_CHT MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)
+#define LANG_CHS MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED)
+
+#define MAKEIMEVERSION(major,minor) ((DWORD) (((BYTE)(major) << 24) | ((BYTE)(minor) << 16) ))
+#define IMEID_VER(id) ((id) & 0xffff0000)
+#define IMEID_LANG(id) ((id) & 0x0000ffff)
+
+#define CHT_HKL_DAYI            ((HKL)0xE0060404)
+#define CHT_HKL_NEW_PHONETIC    ((HKL)0xE0080404)
+#define CHT_HKL_NEW_CHANG_JIE   ((HKL)0xE0090404)
+#define CHT_HKL_NEW_QUICK       ((HKL)0xE00A0404)
+#define CHT_HKL_HK_CANTONESE    ((HKL)0xE00B0404)
+#define CHT_IMEFILENAME1        "TINTLGNT.IME"
+#define CHT_IMEFILENAME2        "CINTLGNT.IME"
+#define CHT_IMEFILENAME3        "MSTCIPHA.IME"
+#define IMEID_CHT_VER42         (LANG_CHT | MAKEIMEVERSION(4, 2))
+#define IMEID_CHT_VER43         (LANG_CHT | MAKEIMEVERSION(4, 3))
+#define IMEID_CHT_VER44         (LANG_CHT | MAKEIMEVERSION(4, 4))
+#define IMEID_CHT_VER50         (LANG_CHT | MAKEIMEVERSION(5, 0))
+#define IMEID_CHT_VER51         (LANG_CHT | MAKEIMEVERSION(5, 1))
+#define IMEID_CHT_VER52         (LANG_CHT | MAKEIMEVERSION(5, 2))
+#define IMEID_CHT_VER60         (LANG_CHT | MAKEIMEVERSION(6, 0))
+#define IMEID_CHT_VER_VISTA     (LANG_CHT | MAKEIMEVERSION(7, 0))
+
+#define CHS_HKL                 ((HKL)0xE00E0804)
+#define CHS_IMEFILENAME1        "PINTLGNT.IME"
+#define CHS_IMEFILENAME2        "MSSCIPYA.IME"
+#define IMEID_CHS_VER41         (LANG_CHS | MAKEIMEVERSION(4, 1))
+#define IMEID_CHS_VER42         (LANG_CHS | MAKEIMEVERSION(4, 2))
+#define IMEID_CHS_VER53         (LANG_CHS | MAKEIMEVERSION(5, 3))
+
+#define LANG() LOWORD((videodata->ime_hkl))
+#define PRIMLANG() ((WORD)PRIMARYLANGID(LANG()))
+#define SUBLANG() SUBLANGID(LANG())
+
+static void IME_UpdateInputLocale(SDL_VideoData *videodata);
+static void IME_ClearComposition(SDL_VideoData *videodata);
+static void IME_SetWindow(SDL_VideoData* videodata, HWND hwnd);
+static void IME_SetupAPI(SDL_VideoData *videodata);
+static DWORD IME_GetId(SDL_VideoData *videodata, UINT uIndex);
+static void IME_SendEditingEvent(SDL_VideoData *videodata);
+#define SDL_IsEqualIID(riid1, riid2) SDL_IsEqualGUID(riid1, riid2)
+#define SDL_IsEqualGUID(rguid1, rguid2) (!SDL_memcmp(rguid1, rguid2, sizeof(GUID)))
+
+static SDL_bool UILess_SetupSinks(SDL_VideoData *videodata);
+static void UILess_ReleaseSinks(SDL_VideoData *videodata);
+static void UILess_EnableUIUpdates(SDL_VideoData *videodata);
+static void UILess_DisableUIUpdates(SDL_VideoData *videodata);
+
+static void
+IME_Init(SDL_VideoData *videodata, HWND hwnd)
+{
+    if (videodata->ime_initialized)
+        return;
+
+    videodata->ime_hwnd_main = hwnd;
+    if (SUCCEEDED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) {
+        videodata->ime_com_initialized = SDL_TRUE;
+        CoCreateInstance(&CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, &IID_ITfThreadMgr, &videodata->ime_threadmgr);
+    }
+    videodata->ime_initialized = SDL_TRUE;
+    videodata->ime_himm32 = LoadLibraryA("imm32.dll");
+    if (!videodata->ime_himm32) {
+        videodata->ime_available = SDL_FALSE;
+        return;
+    }
+    videodata->ImmLockIMC = (LPINPUTCONTEXT2 (WINAPI *)(HIMC))GetProcAddress(videodata->ime_himm32, "ImmLockIMC");
+    videodata->ImmUnlockIMC = (BOOL (WINAPI *)(HIMC))GetProcAddress(videodata->ime_himm32, "ImmUnlockIMC");
+    videodata->ImmLockIMCC = (LPVOID (WINAPI *)(HIMCC))GetProcAddress(videodata->ime_himm32, "ImmLockIMCC");
+    videodata->ImmUnlockIMCC = (BOOL (WINAPI *)(HIMCC))GetProcAddress(videodata->ime_himm32, "ImmUnlockIMCC");
+
+    IME_SetWindow(videodata, hwnd);
+    videodata->ime_himc = ImmGetContext(hwnd);
+    ImmReleaseContext(hwnd, videodata->ime_himc);
+    if (!videodata->ime_himc) {
+        videodata->ime_available = SDL_FALSE;
+        IME_Disable(videodata, hwnd);
+        return;
+    }
+    videodata->ime_available = SDL_TRUE;
+    IME_UpdateInputLocale(videodata);
+    IME_SetupAPI(videodata);
+    videodata->ime_uiless = UILess_SetupSinks(videodata);
+    IME_UpdateInputLocale(videodata);
+    IME_Disable(videodata, hwnd);
+}
+
+static void
+IME_Enable(SDL_VideoData *videodata, HWND hwnd)
+{
+    if (!videodata->ime_initialized || !videodata->ime_hwnd_current)
+        return;
+
+    if (!videodata->ime_available) {
+        IME_Disable(videodata, hwnd);
+        return;
+    }
+    if (videodata->ime_hwnd_current == videodata->ime_hwnd_main)
+        ImmAssociateContext(videodata->ime_hwnd_current, videodata->ime_himc);
+
+    videodata->ime_enabled = SDL_TRUE;
+    IME_UpdateInputLocale(videodata);
+    UILess_EnableUIUpdates(videodata);
+}
+
+static void
+IME_Disable(SDL_VideoData *videodata, HWND hwnd)
+{
+    if (!videodata->ime_initialized || !videodata->ime_hwnd_current)
+        return;
+
+    IME_ClearComposition(videodata);
+    if (videodata->ime_hwnd_current == videodata->ime_hwnd_main)
+        ImmAssociateContext(videodata->ime_hwnd_current, NULL);
+
+    videodata->ime_enabled = SDL_FALSE;
+    UILess_DisableUIUpdates(videodata);
+}
+
+static void
+IME_Quit(SDL_VideoData *videodata)
+{
+    if (!videodata->ime_initialized)
+        return;
+
+    UILess_ReleaseSinks(videodata);
+    if (videodata->ime_hwnd_main)
+        ImmAssociateContext(videodata->ime_hwnd_main, videodata->ime_himc);
+
+    videodata->ime_hwnd_main = 0;
+    videodata->ime_himc = 0;
+    if (videodata->ime_himm32) {
+        FreeLibrary(videodata->ime_himm32);
+        videodata->ime_himm32 = 0;
+    }
+    if (videodata->ime_threadmgr) {
+        videodata->ime_threadmgr->lpVtbl->Release(videodata->ime_threadmgr);
+        videodata->ime_threadmgr = 0;
+    }
+    if (videodata->ime_com_initialized) {
+        CoUninitialize();
+        videodata->ime_com_initialized = SDL_FALSE;
+    }
+    videodata->ime_initialized = SDL_FALSE;
+}
+
+static void
+IME_GetReadingString(SDL_VideoData *videodata, HWND hwnd)
+{
+    DWORD id = 0;
+    HIMC himc = 0;
+    WCHAR buffer[16];
+    WCHAR *s = buffer;
+    DWORD len = 0;
+    DWORD err = 0;
+    BOOL vertical = FALSE;
+    UINT maxuilen = 0;
+    static OSVERSIONINFOA osversion = {0};
+    if (videodata->ime_uiless)
+        return;
+
+    videodata->ime_readingstring[0] = 0;
+    if (!osversion.dwOSVersionInfoSize) {
+        osversion.dwOSVersionInfoSize = sizeof(osversion);
+        GetVersionExA(&osversion);
+    }
+    id = IME_GetId(videodata, 0);
+    if (!id)
+        return;
+
+    himc = ImmGetContext(hwnd);
+    if (!himc)
+        return;
+
+    if (videodata->GetReadingString) {
+        len = videodata->GetReadingString(himc, 0, 0, &err, &vertical, &maxuilen);
+        if (len) {
+            if (len > SDL_arraysize(buffer))
+                len = SDL_arraysize(buffer);
+
+            len = videodata->GetReadingString(himc, len, s, &err, &vertical, &maxuilen);
+        }
+        SDL_wcslcpy(videodata->ime_readingstring, s, len);
+    }
+    else {
+        LPINPUTCONTEXT2 lpimc = videodata->ImmLockIMC(himc);
+        LPBYTE p = 0;
+        s = 0;
+        switch (id)
+        {
+        case IMEID_CHT_VER42:
+        case IMEID_CHT_VER43:
+        case IMEID_CHT_VER44:
+            p = *(LPBYTE *)((LPBYTE)videodata->ImmLockIMCC(lpimc->hPrivate) + 24);
+            if (!p)
+                break;
+
+            len = *(DWORD *)(p + 7*4 + 32*4);
+            s = (WCHAR *)(p + 56);
+            break;
+        case IMEID_CHT_VER51:
+        case IMEID_CHT_VER52:
+        case IMEID_CHS_VER53:
+            p = *(LPBYTE *)((LPBYTE)videodata->ImmLockIMCC(lpimc->hPrivate) + 4);
+            if (!p)
+                break;
+
+            p = *(LPBYTE *)((LPBYTE)p + 1*4 + 5*4);
+            if (!p)
+                break;
+
+            len = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16*2);
+            s = (WCHAR *)(p + 1*4 + (16*2+2*4) + 5*4);
+            break;
+        case IMEID_CHS_VER41:
+            {
+                int offset = (IME_GetId(videodata, 1) >= 0x00000002) ? 8 : 7;
+                p = *(LPBYTE *)((LPBYTE)videodata->ImmLockIMCC(lpimc->hPrivate) + offset * 4);
+                if (!p)
+                    break;
+
+                len = *(DWORD *)(p + 7*4 + 16*2*4);
+                s = (WCHAR *)(p + 6*4 + 16*2*1);
+            }
+            break;
+        case IMEID_CHS_VER42:
+            if (osversion.dwPlatformId != VER_PLATFORM_WIN32_NT)
+                break;
+
+            p = *(LPBYTE *)((LPBYTE)videodata->ImmLockIMCC(lpimc->hPrivate) + 1*4 + 1*4 + 6*4);
+            if (!p)
+                break;
+
+            len = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16*2);
+            s = (WCHAR *)(p + 1*4 + (16*2+2*4) + 5*4);
+            break;
+        }
+        if (s)
+            SDL_wcslcpy(videodata->ime_readingstring, s, len + 1);
+
+        videodata->ImmUnlockIMCC(lpimc->hPrivate);
+        videodata->ImmUnlockIMC(himc);
+    }
+    ImmReleaseContext(hwnd, himc);
+    IME_SendEditingEvent(videodata);
+}
+
+static void
+IME_InputLangChanged(SDL_VideoData *videodata)
+{
+    UINT lang = PRIMLANG();
+    HWND hwndime = 0;
+    IME_UpdateInputLocale(videodata);
+    IME_SetupAPI(videodata);
+    if (lang != PRIMLANG()) {
+        IME_ClearComposition(videodata);
+    }
+    hwndime = ImmGetDefaultIMEWnd(videodata->ime_hwnd_current);
+    if (hwndime) {
+        SendMessageA(hwndime, WM_IME_CONTROL, IMC_OPENSTATUSWINDOW, 0);
+        SendMessageA(hwndime, WM_IME_CONTROL, IMC_CLOSESTATUSWINDOW, 0);
+    }
+}
+
+static DWORD
+IME_GetId(SDL_VideoData *videodata, UINT uIndex)
+{
+    static HKL hklprev = 0;
+    static DWORD dwRet[2] = {0};
+    DWORD dwVerSize = 0;
+    DWORD dwVerHandle = 0;
+    LPVOID lpVerBuffer = 0;
+    LPVOID lpVerData = 0;
+    UINT cbVerData = 0;
+    char szTemp[256];
+    HKL hkl = 0;
+    DWORD dwLang = 0;
+    if (uIndex >= sizeof(dwRet) / sizeof(dwRet[0]))
+        return 0;
+
+    hkl = videodata->ime_hkl;
+    if (hklprev == hkl)
+        return dwRet[uIndex];
+
+    hklprev = hkl;
+    dwLang = ((DWORD)hkl & 0xffff);
+    if (videodata->ime_uiless && LANG() == LANG_CHT) {
+        dwRet[0] = IMEID_CHT_VER_VISTA;
+        dwRet[1] = 0;
+        return dwRet[0];
+    }
+    if (hkl != CHT_HKL_NEW_PHONETIC
+        && hkl != CHT_HKL_NEW_CHANG_JIE
+        && hkl != CHT_HKL_NEW_QUICK
+        && hkl != CHT_HKL_HK_CANTONESE
+        && hkl != CHS_HKL) {
+        dwRet[0] = dwRet[1] = 0;
+        return dwRet[uIndex];
+    }
+    if (ImmGetIMEFileNameA(hkl, szTemp, sizeof(szTemp) - 1) <= 0) {
+        dwRet[0] = dwRet[1] = 0;
+        return dwRet[uIndex];
+    }
+    if (!videodata->GetReadingString) {
+        #define LCID_INVARIANT MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT)
+        if (CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHT_IMEFILENAME1, -1) != 2
+            && CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHT_IMEFILENAME2, -1) != 2
+            && CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHT_IMEFILENAME3, -1) != 2
+            && CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHS_IMEFILENAME1, -1) != 2
+            && CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHS_IMEFILENAME2, -1) != 2) {
+            dwRet[0] = dwRet[1] = 0;
+            return dwRet[uIndex];
+        }
+        #undef LCID_INVARIANT
+        dwVerSize = GetFileVersionInfoSizeA(szTemp, &dwVerHandle);
+        if (dwVerSize) {
+            lpVerBuffer = SDL_malloc(dwVerSize);
+            if (lpVerBuffer) {
+                if (GetFileVersionInfoA(szTemp, dwVerHandle, dwVerSize, lpVerBuffer)) {
+                    if (VerQueryValueA(lpVerBuffer, "\\", &lpVerData, &cbVerData)) {
+                        #define pVerFixedInfo   ((VS_FIXEDFILEINFO FAR*)lpVerData)
+                        DWORD dwVer = pVerFixedInfo->dwFileVersionMS;
+                        dwVer = (dwVer & 0x00ff0000) << 8 | (dwVer & 0x000000ff) << 16;
+                        if (videodata->GetReadingString ||
+                            dwLang == LANG_CHT && (
+                            dwVer == MAKEIMEVERSION(4, 2) ||
+                            dwVer == MAKEIMEVERSION(4, 3) ||
+                            dwVer == MAKEIMEVERSION(4, 4) ||
+                            dwVer == MAKEIMEVERSION(5, 0) ||
+                            dwVer == MAKEIMEVERSION(5, 1) ||
+                            dwVer == MAKEIMEVERSION(5, 2) ||
+                            dwVer == MAKEIMEVERSION(6, 0))
+                            ||
+                            dwLang == LANG_CHS && (
+                            dwVer == MAKEIMEVERSION(4, 1) ||
+                            dwVer == MAKEIMEVERSION(4, 2) ||
+                            dwVer == MAKEIMEVERSION(5, 3))) {
+                            dwRet[0] = dwVer | dwLang;
+                            dwRet[1] = pVerFixedInfo->dwFileVersionLS;
+                            SDL_free(lpVerBuffer);
+                            return dwRet[0];
+                        }
+                        #undef pVerFixedInfo
+                    }
+                }
+            }
+            SDL_free(lpVerBuffer);
+        }
+    }
+    dwRet[0] = dwRet[1] = 0;
+    return dwRet[uIndex];
+}
+
+static void
+IME_SetupAPI(SDL_VideoData *videodata)
+{
+    char ime_file[MAX_PATH + 1];
+    HMODULE hime = 0;
+    HKL hkl = 0;
+    videodata->GetReadingString = 0;
+    videodata->ShowReadingWindow = 0;
+    if (videodata->ime_uiless)
+        return;
+
+    hkl = videodata->ime_hkl;
+    if (ImmGetIMEFileNameA(hkl, ime_file, sizeof(ime_file) - 1) <= 0)
+        return;
+
+    hime = LoadLibraryA(ime_file);
+    if (!hime)
+        return;
+
+    videodata->GetReadingString = (UINT (WINAPI *)(HIMC, UINT, LPWSTR, PINT, BOOL*, PUINT))
+        GetProcAddress(hime, "GetReadingString");
+    videodata->ShowReadingWindow = (BOOL (WINAPI *)(HIMC, BOOL))
+        GetProcAddress(hime, "ShowReadingWindow");
+
+    if (videodata->ShowReadingWindow) {
+        HIMC himc = ImmGetContext(videodata->ime_hwnd_current);
+        if (himc) {
+            videodata->ShowReadingWindow(himc, FALSE);
+            ImmReleaseContext(videodata->ime_hwnd_current, himc);
+        }
+    }
+}
+
+static void
+IME_SetWindow(SDL_VideoData* videodata, HWND hwnd)
+{
+    videodata->ime_hwnd_current = hwnd;
+    if (videodata->ime_threadmgr) {
+        struct ITfDocumentMgr *document_mgr = 0;
+        if (SUCCEEDED(videodata->ime_threadmgr->lpVtbl->AssociateFocus(videodata->ime_threadmgr, hwnd, NULL, &document_mgr))) {
+            if (document_mgr)
+                document_mgr->lpVtbl->Release(document_mgr);
+        }
+    }
+}
+
+static void
+IME_UpdateInputLocale(SDL_VideoData *videodata)
+{
+    static HKL hklprev = 0;
+    videodata->ime_hkl = GetKeyboardLayout(0);
+    if (hklprev == videodata->ime_hkl)
+        return;
+
+    hklprev = videodata->ime_hkl;
+}
+
+static void
+IME_ClearComposition(SDL_VideoData *videodata)
+{
+    HIMC himc = 0;
+    if (!videodata->ime_initialized)
+        return;
+
+    himc = ImmGetContext(videodata->ime_hwnd_current);
+    if (!himc)
+        return;
+
+    ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
+    if (videodata->ime_uiless)
+        ImmSetCompositionString(himc, SCS_SETSTR, TEXT(""), sizeof(TCHAR), TEXT(""), sizeof(TCHAR));
+
+    ImmNotifyIME(himc, NI_CLOSECANDIDATE, 0, 0);
+    ImmReleaseContext(videodata->ime_hwnd_current, himc);
+    SDL_SendEditingText("", 0, 0);
+}
+
+static void
+IME_ClearEditing(SDL_VideoData *videodata)
+{
+
+}
+
+static void
+IME_GetCompositionString(SDL_VideoData *videodata, HIMC himc, DWORD string)
+{
+    LONG length = ImmGetCompositionStringW(himc, string, videodata->ime_composition, sizeof(videodata->ime_composition));
+    if (length < 0)
+        length = 0;
+
+    length /= sizeof(videodata->ime_composition[0]);
+    videodata->ime_cursor = LOWORD(ImmGetCompositionStringW(himc, GCS_CURSORPOS, 0, 0));
+    if (videodata->ime_composition[videodata->ime_cursor] == 0x3000) {
+        int i;
+        for (i = videodata->ime_cursor + 1; i < length; ++i)
+            videodata->ime_composition[i - 1] = videodata->ime_composition[i];
+
+        --length;
+    }
+    videodata->ime_composition[length] = 0;
+}
+
+static void
+IME_SendInputEvent(SDL_VideoData *videodata)
+{
+    char *s = 0;
+    s = WIN_StringToUTF8(videodata->ime_composition);
+    SDL_SendKeyboardText(s);
+    SDL_free(s);
+
+    videodata->ime_composition[0] = 0;
+    videodata->ime_readingstring[0] = 0;
+    videodata->ime_cursor = 0;
+}
+
+static void
+IME_SendEditingEvent(SDL_VideoData *videodata)
+{
+    char *s = 0;
+    WCHAR buffer[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
+    buffer[0] = 0;
+    if (videodata->ime_readingstring[0]) {
+        size_t len = SDL_min(SDL_wcslen(videodata->ime_composition), (size_t)videodata->ime_cursor);
+        SDL_wcslcpy(buffer, videodata->ime_composition, len + 1);
+        SDL_wcslcat(buffer, videodata->ime_readingstring, sizeof(buffer));
+        SDL_wcslcat(buffer, &videodata->ime_composition[len], sizeof(buffer) - len);
+    }
+    else {
+        SDL_wcslcpy(buffer, videodata->ime_composition, sizeof(videodata->ime_composition));
+    }
+    s = WIN_StringToUTF8(buffer);
+    SDL_SendEditingText(s, videodata->ime_cursor + SDL_wcslen(videodata->ime_readingstring), 0);
+    SDL_free(s);
+}
+
+SDL_bool
+IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoData *videodata)
+{
+    SDL_bool trap = SDL_FALSE;
+    HIMC himc = 0;
+    if (!videodata->ime_initialized || !videodata->ime_available || !videodata->ime_enabled)
+        return SDL_FALSE;
+
+    switch (msg)
+    {
+    case WM_INPUTLANGCHANGE:
+        //IME_InputLangChanged(videodata);
+        break;
+    case WM_IME_SETCONTEXT:
+        *lParam = 0;
+        break;
+    case WM_IME_STARTCOMPOSITION:
+        trap = SDL_TRUE;
+        break;
+    case WM_IME_COMPOSITION:
+        trap = SDL_TRUE;
+        himc = ImmGetContext(hwnd);
+        if (*lParam & GCS_RESULTSTR) {
+            IME_GetCompositionString(videodata, himc, GCS_RESULTSTR);
+            IME_SendInputEvent(videodata);
+        }
+        if (*lParam & GCS_COMPSTR) {
+            if (!videodata->ime_uiless)
+                videodata->ime_readingstring[0] = 0;
+
+            IME_GetCompositionString(videodata, himc, GCS_COMPSTR);
+            IME_SendEditingEvent(videodata);
+        }
+        ImmReleaseContext(hwnd, himc);
+        break;
+    case WM_IME_ENDCOMPOSITION:
+        videodata->ime_composition[0] = 0;
+        videodata->ime_readingstring[0] = 0;
+        videodata->ime_cursor = 0;
+        SDL_SendEditingText("", 0, 0);
+        break;
+    case WM_IME_NOTIFY:
+        switch (wParam)
+        {
+        case IMN_SETCONVERSIONMODE:
+        case IMN_SETOPENSTATUS:
+            IME_UpdateInputLocale(videodata);
+            break;
+        case IMN_OPENCANDIDATE:
+        case IMN_CHANGECANDIDATE:
+            trap = SDL_TRUE;
+            break;
+        case IMN_CLOSECANDIDATE:
+            trap = SDL_TRUE;
+            break;
+        case IMN_PRIVATE:
+            {
+                DWORD dwId = IME_GetId(videodata, 0);
+                IME_GetReadingString(videodata, hwnd);
+                switch (dwId)
+                {
+                case IMEID_CHT_VER42:
+                case IMEID_CHT_VER43:
+                case IMEID_CHT_VER44:
+                case IMEID_CHS_VER41:
+                case IMEID_CHS_VER42:
+                    if (*lParam == 1 || *lParam == 2)
+                        trap = SDL_TRUE;
+
+                    break;
+                case IMEID_CHT_VER50:
+                case IMEID_CHT_VER51:
+                case IMEID_CHT_VER52:
+                case IMEID_CHT_VER60:
+                case IMEID_CHS_VER53:
+                    if (*lParam == 16
+                        || *lParam == 17
+                        || *lParam == 26
+                        || *lParam == 27
+                        || *lParam == 28)
+                        trap = SDL_TRUE;
+                    break;
+                }
+            }
+            break;
+        default:
+            trap = SDL_TRUE;
+            break;
+        }
+        break;
+    }
+    return trap;
+}
+
+STDMETHODIMP_(ULONG) TSFSink_AddRef(TSFSink *sink)
+{
+    return ++sink->refcount;
+}
+
+STDMETHODIMP_(ULONG)TSFSink_Release(TSFSink *sink)
+{
+    --sink->refcount;
+    if (sink->refcount == 0)
+    {
+        SDL_free(sink);
+        return 0;
+    }
+    return sink->refcount;
+}
+
+STDMETHODIMP UIElementSink_QueryInterface(TSFSink *sink, REFIID riid, PVOID *ppv)
+{
+    if (!ppv)
+        return E_INVALIDARG;
+
+    *ppv = 0;
+    if (SDL_IsEqualIID(riid, &IID_IUnknown))
+        *ppv = (IUnknown *)sink;
+    else if (SDL_IsEqualIID(riid, &IID_ITfUIElementSink))
+        *ppv = (ITfUIElementSink *)sink;
+
+    if (*ppv) {
+        TSFSink_AddRef(sink);
+        return S_OK;
+    }
+    return E_NOINTERFACE;
+}
+
+ITfUIElement *UILess_GetUIElement(SDL_VideoData *videodata, DWORD dwUIElementId)
+{
+    ITfUIElementMgr *puiem = 0;
+    ITfUIElement *pelem = 0;
+    ITfThreadMgrEx *threadmgrex = videodata->ime_threadmgrex;
+
+    if (SUCCEEDED(threadmgrex->lpVtbl->QueryInterface(threadmgrex, &IID_ITfUIElementMgr, (LPVOID *)&puiem))) {
+        puiem->lpVtbl->GetUIElement(puiem, dwUIElementId, &pelem);
+        puiem->lpVtbl->Release(puiem);
+    }
+    return pelem;
+}
+
+STDMETHODIMP UIElementSink_BeginUIElement(TSFSink *sink, DWORD dwUIElementId, BOOL *pbShow)
+{
+    ITfUIElement *element = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId);
+    ITfReadingInformationUIElement *preading = 0;
+    SDL_VideoData *videodata = (SDL_VideoData *)sink->data;
+    if (!element)
+        return E_INVALIDARG;
+
+    *pbShow = FALSE;
+    if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfReadingInformationUIElement, (LPVOID *)&preading))) {
+        BSTR bstr;
+        if (SUCCEEDED(preading->lpVtbl->GetString(preading, &bstr)) && bstr) {
+            WCHAR *s = (WCHAR *)bstr;
+            SysFreeString(bstr);
+        }
+        preading->lpVtbl->Release(preading);
+    }
+    return S_OK;
+}
+
+STDMETHODIMP UIElementSink_UpdateUIElement(TSFSink *sink, DWORD dwUIElementId)
+{
+    ITfUIElement *element = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId);
+    ITfReadingInformationUIElement *preading = 0;
+    SDL_VideoData *videodata = (SDL_VideoData *)sink->data;
+    if (!element)
+        return E_INVALIDARG;
+
+    if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfReadingInformationUIElement, (LPVOID *)&preading))) {
+        BSTR bstr;
+        if (SUCCEEDED(preading->lpVtbl->GetString(preading, &bstr)) && bstr) {
+            WCHAR *s = (WCHAR *)bstr;
+            SDL_wcslcpy(videodata->ime_readingstring, s, sizeof(videodata->ime_readingstring));
+            IME_SendEditingEvent(videodata);
+            SysFreeString(bstr);
+        }
+        preading->lpVtbl->Release(preading);
+    }
+    return S_OK;
+}
+
+STDMETHODIMP UIElementSink_EndUIElement(TSFSink *sink, DWORD dwUIElementId)
+{
+    ITfUIElement *element = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId);
+    ITfReadingInformationUIElement *preading = 0;
+    SDL_VideoData *videodata = (SDL_VideoData *)sink->data;
+    if (!element)
+        return E_INVALIDARG;
+
+    if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfReadingInformationUIElement, (LPVOID *)&preading))) {
+        videodata->ime_readingstring[0] = 0;
+        IME_SendEditingEvent(videodata);
+        preading->lpVtbl->Release(preading);
+    }
+    return S_OK;
+}
+
+STDMETHODIMP IPPASink_QueryInterface(TSFSink *sink, REFIID riid, PVOID *ppv)
+{
+    if (!ppv)
+        return E_INVALIDARG;
+
+    *ppv = 0;
+    if (SDL_IsEqualIID(riid, &IID_IUnknown))
+        *ppv = (IUnknown *)sink;
+    else if (SDL_IsEqualIID(riid, &IID_ITfInputProcessorProfileActivationSink))
+        *ppv = (ITfInputProcessorProfileActivationSink *)sink;
+
+    if (*ppv) {
+        TSFSink_AddRef(sink);
+        return S_OK;
+    }
+    return E_NOINTERFACE;
+}
+
+STDMETHODIMP IPPASink_OnActivated(TSFSink *sink, DWORD dwProfileType, LANGID langid, REFCLSID clsid, REFGUID catid, REFGUID guidProfile, HKL hkl, DWORD dwFlags)
+{
+    if (SDL_IsEqualIID(catid, &GUID_TFCAT_TIP_KEYBOARD) && (dwFlags & TF_IPSINK_FLAG_ACTIVE))
+        IME_InputLangChanged((SDL_VideoData *)sink->data);
+
+    return S_OK;
+}
+
+static void *vtUIElementSink[] = {
+    (void *)(UIElementSink_QueryInterface),
+    (void *)(TSFSink_AddRef),
+    (void *)(TSFSink_Release),
+    (void *)(UIElementSink_BeginUIElement),
+    (void *)(UIElementSink_UpdateUIElement),
+    (void *)(UIElementSink_EndUIElement)
+};
+
+static void *vtIPPASink[] = {
+    (void *)(IPPASink_QueryInterface),
+    (void *)(TSFSink_AddRef),
+    (void *)(TSFSink_Release),
+    (void *)(IPPASink_OnActivated)
+};
+
+static void
+UILess_EnableUIUpdates(SDL_VideoData *videodata)
+{
+    ITfSource *source = 0;
+    if (!videodata->ime_threadmgrex || videodata->ime_uielemsinkcookie != TF_INVALID_COOKIE)
+        return;
+
+    if (SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, (LPVOID *)&source))) {
+        source->lpVtbl->AdviseSink(source, &IID_ITfUIElementSink, (IUnknown *)videodata->ime_uielemsink, &videodata->ime_uielemsinkcookie);
+        source->lpVtbl->Release(source);
+    }
+}
+
+static void
+UILess_DisableUIUpdates(SDL_VideoData *videodata)
+{
+    ITfSource *source = 0;
+    if (!videodata->ime_threadmgrex || videodata->ime_uielemsinkcookie == TF_INVALID_COOKIE)
+        return;
+
+    if (SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, (LPVOID *)&source))) {
+        source->lpVtbl->UnadviseSink(source, videodata->ime_uielemsinkcookie);
+        videodata->ime_uielemsinkcookie = TF_INVALID_COOKIE;
+        source->lpVtbl->Release(source);
+    }
+}
+
+static SDL_bool
+UILess_SetupSinks(SDL_VideoData *videodata)
+{
+    TfClientId clientid = 0;
+    SDL_bool result = SDL_FALSE;
+    ITfSource *source = 0;
+    if (FAILED(CoCreateInstance(&CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, &IID_ITfThreadMgrEx, &videodata->ime_threadmgrex)))
+        return SDL_FALSE;
+
+    if (FAILED(videodata->ime_threadmgrex->lpVtbl->ActivateEx(videodata->ime_threadmgrex, &clientid, TF_TMAE_UIELEMENTENABLEDONLY)))
+        return SDL_FALSE;
+
+    videodata->ime_uielemsink = SDL_malloc(sizeof(TSFSink));
+    videodata->ime_ippasink = SDL_malloc(sizeof(TSFSink));
+
+    videodata->ime_uielemsink->lpVtbl = vtUIElementSink;
+    videodata->ime_uielemsink->refcount = 1;
+    videodata->ime_uielemsink->data = videodata;
+
+    videodata->ime_ippasink->lpVtbl = vtIPPASink;
+    videodata->ime_ippasink->refcount = 1;
+    videodata->ime_ippasink->data = videodata;
+
+    if (SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, (LPVOID *)&source))) {
+        if (SUCCEEDED(source->lpVtbl->AdviseSink(source, &IID_ITfUIElementSink, (IUnknown *)videodata->ime_uielemsink, &videodata->ime_uielemsinkcookie))) {
+            if (SUCCEEDED(source->lpVtbl->AdviseSink(source, &IID_ITfInputProcessorProfileActivationSink, (IUnknown *)videodata->ime_ippasink, &videodata->ime_alpnsinkcookie))) {
+                result = SDL_TRUE;
+            }
+        }
+        source->lpVtbl->Release(source);
+    }
+    return result;
+}
+
+#define SAFE_RELEASE(p)                             \
+{                                                   \
+    if (p) {                                        \
+        (p)->lpVtbl->Release((p));                  \
+        (p) = 0;                                    \
+    }                                               \
+}
+
+static void
+UILess_ReleaseSinks(SDL_VideoData *videodata)
+{
+    ITfSource *source = 0;
+    if (videodata->ime_threadmgrex && SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, &source))) {
+        source->lpVtbl->UnadviseSink(source, videodata->ime_uielemsinkcookie);
+        source->lpVtbl->UnadviseSink(source, videodata->ime_alpnsinkcookie);
+        SAFE_RELEASE(source);
+        videodata->ime_threadmgrex->lpVtbl->Deactivate(videodata->ime_threadmgrex);
+        SAFE_RELEASE(videodata->ime_threadmgrex);
+        TSFSink_Release(videodata->ime_uielemsink);
+        videodata->ime_uielemsink = 0;
+        TSFSink_Release(videodata->ime_ippasink);
+        videodata->ime_ippasink = 0;
+    }
 }
 
 /* vi: set ts=4 sw=4 expandtab: */
--- a/src/video/win32/SDL_win32keyboard.h	Sun Aug 22 12:35:34 2010 -0700
+++ b/src/video/win32/SDL_win32keyboard.h	Sun Aug 22 12:39:27 2010 -0700
@@ -31,6 +31,12 @@
 extern void WIN_UpdateKeymap(void);
 extern void WIN_QuitKeyboard(_THIS);
 
+extern void WIN_StartTextInput(_THIS);
+extern void WIN_StopTextInput(_THIS);
+extern void WIN_SetTextInputRect(_THIS, SDL_Rect *rect);
+
+extern SDL_bool IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, struct SDL_VideoData *videodata);
+
 #endif /* _SDL_win32keyboard_h */
 
 /* vi: set ts=4 sw=4 expandtab: */
--- a/src/video/win32/SDL_win32video.c	Sun Aug 22 12:35:34 2010 -0700
+++ b/src/video/win32/SDL_win32video.c	Sun Aug 22 12:39:27 2010 -0700
@@ -191,6 +191,9 @@
     device->GL_SwapWindow = WIN_GL_SwapWindow;
     device->GL_DeleteContext = WIN_GL_DeleteContext;
 #endif
+    device->StartTextInput = WIN_StartTextInput;
+    device->StopTextInput = WIN_StopTextInput;
+    device->SetTextInputRect = WIN_SetTextInputRect;
 
     device->SetClipboardText = WIN_SetClipboardText;
     device->GetClipboardText = WIN_GetClipboardText;
--- a/src/video/win32/SDL_win32video.h	Sun Aug 22 12:35:34 2010 -0700
+++ b/src/video/win32/SDL_win32video.h	Sun Aug 22 12:39:27 2010 -0700
@@ -42,6 +42,8 @@
 
 #include <windows.h>
 
+#include <msctf.h>
+
 #if SDL_VIDEO_RENDER_D3D
 //#include <d3d9.h>
 #define D3D_DEBUG_INFO
@@ -62,6 +64,7 @@
 #include "SDL_win32mouse.h"
 #include "SDL_win32opengl.h"
 #include "SDL_win32window.h"
+#include "SDL_events.h"
 
 #ifdef UNICODE
 #define WIN_StringToUTF8(S) SDL_iconv_string("UTF-8", "UCS-2", (char *)S, (SDL_wcslen(S)+1)*sizeof(WCHAR))
@@ -77,6 +80,37 @@
 typedef BOOL  (*PFNSHFullScreen)(HWND, DWORD);
 typedef void  (*PFCoordTransform)(SDL_Window*, POINT*);
 
+typedef struct  
+{
+    void **lpVtbl;
+    int refcount;
+    void *data;
+} TSFSink;
+
+// Definition from Win98DDK version of IMM.H
+typedef struct tagINPUTCONTEXT2 {
+    HWND                hWnd;                           
+    BOOL                fOpen;                          
+    POINT               ptStatusWndPos;                 
+    POINT               ptSoftKbdPos;                   
+    DWORD               fdwConversion;                  
+    DWORD               fdwSentence;                    
+    union   {                                           
+        LOGFONTA        A;                              
+        LOGFONTW        W;                              
+    } lfFont;                                           
+    COMPOSITIONFORM     cfCompForm;                     
+    CANDIDATEFORM       cfCandForm[4];                  
+    HIMCC               hCompStr;                       
+    HIMCC               hCandInfo;                      
+    HIMCC               hGuideLine;                     
+    HIMCC               hPrivate;                       
+    DWORD               dwNumMsgBuf;                    
+    HIMCC               hMsgBuf;                        
+    DWORD               fdwInit;                        
+    DWORD               dwReserve[3];                   
+} INPUTCONTEXT2, *PINPUTCONTEXT2, NEAR *NPINPUTCONTEXT2, FAR *LPINPUTCONTEXT2;  
+
 /* Private display data */
 
 typedef struct SDL_VideoData
@@ -97,9 +131,39 @@
     PFCoordTransform CoordTransform;
 #endif
 
+    const SDL_scancode *key_layout;
     DWORD clipboard_count;
 
-    const SDL_scancode *key_layout;
+    SDL_bool ime_com_initialized;
+    struct ITfThreadMgr *ime_threadmgr;
+    SDL_bool ime_initialized;
+    SDL_bool ime_enabled;
+    SDL_bool ime_available;
+    HWND ime_hwnd_main;
+    HWND ime_hwnd_current;
+    HIMC ime_himc;
+
+    WCHAR ime_composition[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
+    WCHAR ime_readingstring[16];
+    int ime_cursor;
+
+    HKL ime_hkl;
+    HMODULE ime_himm32;
+    UINT (WINAPI *GetReadingString)(HIMC himc, UINT uReadingBufLen, LPWSTR lpwReadingBuf, PINT pnErrorIndex, BOOL *pfIsVertical, PUINT puMaxReadingLen);
+    BOOL (WINAPI *ShowReadingWindow)(HIMC himc, BOOL bShow);
+    LPINPUTCONTEXT2 (WINAPI *ImmLockIMC)(HIMC himc);
+    BOOL (WINAPI *ImmUnlockIMC)(HIMC himc);
+    LPVOID (WINAPI *ImmLockIMCC)(HIMCC himcc);
+    BOOL (WINAPI *ImmUnlockIMCC)(HIMCC himcc);
+
+    SDL_bool ime_uiless;
+    struct ITfThreadMgrEx *ime_threadmgrex;
+    DWORD ime_uielemsinkcookie;
+    DWORD ime_alpnsinkcookie;
+    DWORD ime_openmodesinkcookie;
+    DWORD ime_convmodesinkcookie;
+    TSFSink *ime_uielemsink;
+    TSFSink *ime_ippasink;
 } SDL_VideoData;
 
 #endif /* _SDL_win32video_h */
--- a/src/video/win32/SDL_win32window.c	Sun Aug 22 12:35:34 2010 -0700
+++ b/src/video/win32/SDL_win32window.c	Sun Aug 22 12:39:27 2010 -0700
@@ -77,10 +77,12 @@
 
     /* Set up the window proc function */
     data->wndproc = (WNDPROC) GetWindowLongPtr(hwnd, GWLP_WNDPROC);
-    if (data->wndproc == DefWindowProc) {
+    if (data->wndproc == WIN_WindowProc) {
         data->wndproc = NULL;
     }
-    SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) WIN_WindowProc);
+    else {
+        SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) WIN_WindowProc);
+    }
 
     /* Fill in the SDL window with the window data */
     {
--- a/test/testime.c	Sun Aug 22 12:35:34 2010 -0700
+++ b/test/testime.c	Sun Aug 22 12:39:27 2010 -0700
@@ -25,7 +25,49 @@
 SDL_Rect textRect, markedRect;
 Uint32 lineColor, backColor;
 SDL_Color textColor = { 0, 0, 0 };
-char text[MAX_TEXT_LENGTH], *markedText;
+char text[MAX_TEXT_LENGTH], markedText[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
+int cursor = 0;
+
+size_t utf8_length(unsigned char c)
+{
+    c = (unsigned char)(0xff & c);
+    if (c < 0x80)
+        return 1;
+    else if ((c >> 5) ==0x6)
+        return 2;
+    else if ((c >> 4) == 0xe)
+        return 3;
+    else if ((c >> 3) == 0x1e)
+        return 4;
+    else
+        return 0;
+}
+
+char *utf8_next(char *p)
+{
+    size_t len = utf8_length(*p);
+    size_t i = 0;
+    if (!len)
+        return 0;
+
+    for (; i < len; ++i)
+    {
+        ++p;
+        if (!*p)
+            return 0;
+    }
+    return p;
+}
+
+char *utf8_advance(char *p, size_t distance)
+{
+    size_t i = 0;
+    for (; i < distance && p; ++i)
+    {
+        p = utf8_next(p);
+    }
+    return p;
+}
 
 void usage()
 {
@@ -124,7 +166,7 @@
 
     text[0] = 0;
     markedRect = textRect;
-    markedText = NULL;
+    markedText[0] = 0;
 
     SDL_StartTextInput();
 }
@@ -180,9 +222,22 @@
     cursorRect.h = h;
 
     SDL_FillRect(screen, &markedRect, backColor);
-    if (markedText)
+    if (markedText[0])
     {
 #ifdef HAVE_SDL_TTF
+        if (cursor)
+        {
+            char *p = utf8_advance(markedText, cursor);
+            char c = 0;
+            if (!p)
+                p = &markedText[strlen(markedText)];
+
+            c = *p;
+            *p = 0;
+            TTF_SizeUTF8(font, markedText, &w, 0);
+            cursorRect.x += w;
+            *p = c;
+        }
         RenderText(screen, font, markedText, markedRect.x, markedRect.y, textColor);
         TTF_SizeUTF8(font, markedText, &w, &h);
 #endif
@@ -192,8 +247,6 @@
         underlineRect.h = 2;
         underlineRect.w = w;
 
-        cursorRect.x += w + 1;
-
         SDL_FillRect(screen, &underlineRect, lineColor);
     }
 
@@ -295,13 +348,13 @@
             fprintf(stderr, "Keyboard: text input \"%s\"\n", event.text.text);
 
             if (SDL_strlen(text) + SDL_strlen(event.text.text) < sizeof(text))
-                SDL_strlcpy(text + SDL_strlen(text), event.text.text, sizeof(text));
+                SDL_strlcat(text, event.text.text, sizeof(text));
 
             fprintf(stderr, "text inputed: %s\n", text);
 
             // After text inputed, we can clear up markedText because it
             // is committed
-            markedText = NULL;
+            markedText[0] = 0;
             Redraw();
             break;
 
@@ -309,7 +362,8 @@
             fprintf(stderr, "text editing \"%s\", selected range (%d, %d)\n",
                     event.edit.text, event.edit.start, event.edit.length);
 
-            markedText = event.edit.text;
+            strcpy(markedText, event.edit.text);
+            cursor = event.edit.start;
             Redraw();
             break;