diff --git a/EXCLUDE/GLIMM/GLIMM.sln b/EXCLUDE/GLIMM/GLIMM.sln
new file mode 100644
index 000000000..6dd674eef
--- /dev/null
+++ b/EXCLUDE/GLIMM/GLIMM.sln
@@ -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
diff --git a/EXCLUDE/GLIMM/GLIMM.vcproj b/EXCLUDE/GLIMM/GLIMM.vcproj
new file mode 100644
index 000000000..5949e86d4
--- /dev/null
+++ b/EXCLUDE/GLIMM/GLIMM.vcproj
@@ -0,0 +1,233 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/EXCLUDE/GLIMM/include/App.hpp b/EXCLUDE/GLIMM/include/App.hpp
new file mode 100644
index 000000000..5c9ff3efa
--- /dev/null
+++ b/EXCLUDE/GLIMM/include/App.hpp
@@ -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
diff --git a/EXCLUDE/GLIMM/include/IMM.hpp b/EXCLUDE/GLIMM/include/IMM.hpp
new file mode 100644
index 000000000..45be3d61f
--- /dev/null
+++ b/EXCLUDE/GLIMM/include/IMM.hpp
@@ -0,0 +1,41 @@
+#ifndef IMM_HPP
+#define IMM_HPP
+
+#define WIN32_LEAN_AND_MEAN
+#include
+#include
+
+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
diff --git a/EXCLUDE/GLIMM/include/Video_Mode.hpp b/EXCLUDE/GLIMM/include/Video_Mode.hpp
new file mode 100644
index 000000000..00a801400
--- /dev/null
+++ b/EXCLUDE/GLIMM/include/Video_Mode.hpp
@@ -0,0 +1,30 @@
+#ifndef VIDEO_MODE_HPP
+#define VIDEO_MODE_HPP
+
+#include
+
+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
diff --git a/EXCLUDE/GLIMM/include/Window.hpp b/EXCLUDE/GLIMM/include/Window.hpp
new file mode 100644
index 000000000..dc465d421
--- /dev/null
+++ b/EXCLUDE/GLIMM/include/Window.hpp
@@ -0,0 +1,63 @@
+#ifndef WINDOW_HPP
+#define WINDOW_HPP
+
+#include
+
+#define WIN32_LEAN_AND_MEAN
+#include
+
+#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
diff --git a/EXCLUDE/GLIMM/include/Window_Listener.hpp b/EXCLUDE/GLIMM/include/Window_Listener.hpp
new file mode 100644
index 000000000..206dd50ba
--- /dev/null
+++ b/EXCLUDE/GLIMM/include/Window_Listener.hpp
@@ -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
diff --git a/EXCLUDE/GLIMM/src/App.cpp b/EXCLUDE/GLIMM/src/App.cpp
new file mode 100644
index 000000000..393ac5b88
--- /dev/null
+++ b/EXCLUDE/GLIMM/src/App.cpp
@@ -0,0 +1,113 @@
+#include "App.hpp"
+#include
+#include
+
+#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();
+}
diff --git a/EXCLUDE/GLIMM/src/IMM.cpp b/EXCLUDE/GLIMM/src/IMM.cpp
new file mode 100644
index 000000000..c949ae4a5
--- /dev/null
+++ b/EXCLUDE/GLIMM/src/IMM.cpp
@@ -0,0 +1,237 @@
+#include "IMM.hpp"
+#include
+
+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(&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);
+ }
+}
diff --git a/EXCLUDE/GLIMM/src/Main.cpp b/EXCLUDE/GLIMM/src/Main.cpp
new file mode 100644
index 000000000..26c975da4
--- /dev/null
+++ b/EXCLUDE/GLIMM/src/Main.cpp
@@ -0,0 +1,24 @@
+#include "App.hpp"
+#include
+
+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;
+}
diff --git a/EXCLUDE/GLIMM/src/Video_Mode.cpp b/EXCLUDE/GLIMM/src/Video_Mode.cpp
new file mode 100644
index 000000000..177e8b956
--- /dev/null
+++ b/EXCLUDE/GLIMM/src/Video_Mode.cpp
@@ -0,0 +1,100 @@
+#include "Video_Mode.hpp"
+#include
+#include
+#define WIN32_LEAN_AND_MEAN
+#include
+
+namespace
+{
+
+ typedef std::vector 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());
+ }
+}
diff --git a/EXCLUDE/GLIMM/src/Window.cpp b/EXCLUDE/GLIMM/src/Window.cpp
new file mode 100644
index 000000000..eb59121ab
--- /dev/null
+++ b/EXCLUDE/GLIMM/src/Window.cpp
@@ -0,0 +1,317 @@
+#include "Window.hpp"
+#include
+
+#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(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(reinterpret_cast(lParam)->lpCreateParams);
+ SetWindowLongPtr(Handle, GWLP_USERDATA, This);
+ return 0;
+ }
+ break;
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return 0;
+ break;
+ default:
+ {
+ Window* Win = reinterpret_cast(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;
+}
diff --git a/EXCLUDE/GLTSF/GLTSF.sln b/EXCLUDE/GLTSF/GLTSF.sln
new file mode 100644
index 000000000..f69c11422
--- /dev/null
+++ b/EXCLUDE/GLTSF/GLTSF.sln
@@ -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
diff --git a/EXCLUDE/GLTSF/GLTSF.vcproj b/EXCLUDE/GLTSF/GLTSF.vcproj
new file mode 100644
index 000000000..25c8a75bd
--- /dev/null
+++ b/EXCLUDE/GLTSF/GLTSF.vcproj
@@ -0,0 +1,231 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/EXCLUDE/GLTSF/GLTSF.vcxproj b/EXCLUDE/GLTSF/GLTSF.vcxproj
new file mode 100644
index 000000000..bc2928c22
--- /dev/null
+++ b/EXCLUDE/GLTSF/GLTSF.vcxproj
@@ -0,0 +1,99 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+
+ {790D58BA-E5F6-4286-A9C6-0DC28779789D}
+ Win32Proj
+ GLTSF
+
+
+
+ Application
+ true
+ Unicode
+
+
+ Application
+ false
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(SolutionDir)bin\
+ obj\$(Configuration)\
+
+
+ false
+ $(SolutionDir)bin\
+ obj\$(Configuration)\
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ include;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ include;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/EXCLUDE/GLTSF/GLTSF.vcxproj.filters b/EXCLUDE/GLTSF/GLTSF.vcxproj.filters
new file mode 100644
index 000000000..acab9f8e0
--- /dev/null
+++ b/EXCLUDE/GLTSF/GLTSF.vcxproj.filters
@@ -0,0 +1,51 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/EXCLUDE/GLTSF/GLTSF_vs2008.sln b/EXCLUDE/GLTSF/GLTSF_vs2008.sln
new file mode 100644
index 000000000..319a4c0db
--- /dev/null
+++ b/EXCLUDE/GLTSF/GLTSF_vs2008.sln
@@ -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
diff --git a/EXCLUDE/GLTSF/include/App.hpp b/EXCLUDE/GLTSF/include/App.hpp
new file mode 100644
index 000000000..88cdf41da
--- /dev/null
+++ b/EXCLUDE/GLTSF/include/App.hpp
@@ -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
diff --git a/EXCLUDE/GLTSF/include/TSF.hpp b/EXCLUDE/GLTSF/include/TSF.hpp
new file mode 100644
index 000000000..f6f3fbea8
--- /dev/null
+++ b/EXCLUDE/GLTSF/include/TSF.hpp
@@ -0,0 +1,83 @@
+#ifndef TSF_HPP
+#define TSF_HPP
+
+#include
+#include
+
+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 my_Document_Manager;
+ CComPtr my_Context;
+ DWORD my_Edit_Cookie;
+ CComPtr my_Sink;
+ DWORD my_Sink_Mask;
+ DWORD my_Lock;
+ DWORD my_Lock_Queued;
+ CComPtr my_Composition_View;
+ TS_SELECTION_ACP my_Composition_Selection;
+ };
+
+ TSF();
+
+ static bool COM_Initialized;
+
+ static CComPtr Thread_Manager;
+ static TfClientId Client_Id;
+ static TSF_Text_Store *Text_Store;
+};
+
+#endif
diff --git a/EXCLUDE/GLTSF/include/Video_Mode.hpp b/EXCLUDE/GLTSF/include/Video_Mode.hpp
new file mode 100644
index 000000000..00a801400
--- /dev/null
+++ b/EXCLUDE/GLTSF/include/Video_Mode.hpp
@@ -0,0 +1,30 @@
+#ifndef VIDEO_MODE_HPP
+#define VIDEO_MODE_HPP
+
+#include
+
+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
diff --git a/EXCLUDE/GLTSF/include/Window.hpp b/EXCLUDE/GLTSF/include/Window.hpp
new file mode 100644
index 000000000..f019cd268
--- /dev/null
+++ b/EXCLUDE/GLTSF/include/Window.hpp
@@ -0,0 +1,59 @@
+#ifndef WINDOW_HPP
+#define WINDOW_HPP
+
+#include
+
+#define WIN32_LEAN_AND_MEAN
+#include
+
+#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
diff --git a/EXCLUDE/GLTSF/include/Window_Listener.hpp b/EXCLUDE/GLTSF/include/Window_Listener.hpp
new file mode 100644
index 000000000..a5a96e731
--- /dev/null
+++ b/EXCLUDE/GLTSF/include/Window_Listener.hpp
@@ -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
diff --git a/EXCLUDE/GLTSF/src/App.cpp b/EXCLUDE/GLTSF/src/App.cpp
new file mode 100644
index 000000000..feb8be51c
--- /dev/null
+++ b/EXCLUDE/GLTSF/src/App.cpp
@@ -0,0 +1,105 @@
+#include "App.hpp"
+#include "TSF.hpp"
+#include
+#include
+
+#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();
+}
diff --git a/EXCLUDE/GLTSF/src/Main.cpp b/EXCLUDE/GLTSF/src/Main.cpp
new file mode 100644
index 000000000..26c975da4
--- /dev/null
+++ b/EXCLUDE/GLTSF/src/Main.cpp
@@ -0,0 +1,24 @@
+#include "App.hpp"
+#include
+
+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;
+}
diff --git a/EXCLUDE/GLTSF/src/TSF.cpp b/EXCLUDE/GLTSF/src/TSF.cpp
new file mode 100644
index 000000000..4060397ff
--- /dev/null
+++ b/EXCLUDE/GLTSF/src/TSF.cpp
@@ -0,0 +1,360 @@
+#include "TSF.hpp"
+#include
+
+bool TSF::COM_Initialized = false;
+CComPtr 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(&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(this);
+ else if (IID_ITfContextOwnerCompositionSink == riid)
+ *ppvObject = static_cast(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 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 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(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()
+{
+
+}
diff --git a/EXCLUDE/GLTSF/src/Video_Mode.cpp b/EXCLUDE/GLTSF/src/Video_Mode.cpp
new file mode 100644
index 000000000..177e8b956
--- /dev/null
+++ b/EXCLUDE/GLTSF/src/Video_Mode.cpp
@@ -0,0 +1,100 @@
+#include "Video_Mode.hpp"
+#include
+#include
+#define WIN32_LEAN_AND_MEAN
+#include
+
+namespace
+{
+
+ typedef std::vector 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());
+ }
+}
diff --git a/EXCLUDE/GLTSF/src/Window.cpp b/EXCLUDE/GLTSF/src/Window.cpp
new file mode 100644
index 000000000..0160d65ec
--- /dev/null
+++ b/EXCLUDE/GLTSF/src/Window.cpp
@@ -0,0 +1,281 @@
+#include "Window.hpp"
+#include
+
+#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(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(reinterpret_cast(lParam)->lpCreateParams);
+ SetWindowLongPtr(Handle, GWLP_USERDATA, This);
+ return 0;
+ }
+ break;
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return 0;
+ break;
+ default:
+ {
+ Window* Win = reinterpret_cast(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);
+}
diff --git a/VisualC/tests/automated/automated_VS2008.vcproj b/VisualC/tests/automated/automated_VS2008.vcproj
old mode 100755
new mode 100644
diff --git a/VisualC/tests/checkkeys/checkkeys_VS2005.vcproj b/VisualC/tests/checkkeys/checkkeys_VS2005.vcproj
old mode 100755
new mode 100644
diff --git a/VisualC/tests/graywin/graywin_VS2005.vcproj b/VisualC/tests/graywin/graywin_VS2005.vcproj
old mode 100755
new mode 100644
diff --git a/VisualC/tests/loopwave/loopwave_VS2005.vcproj b/VisualC/tests/loopwave/loopwave_VS2005.vcproj
old mode 100755
new mode 100644
diff --git a/VisualC/tests/testalpha/testalpha_VS2005.vcproj b/VisualC/tests/testalpha/testalpha_VS2005.vcproj
old mode 100755
new mode 100644
diff --git a/VisualC/tests/testdraw2/testdraw2_VS2005.vcproj b/VisualC/tests/testdraw2/testdraw2_VS2005.vcproj
old mode 100755
new mode 100644
diff --git a/VisualC/tests/testfile/testfile_VS2005.vcproj b/VisualC/tests/testfile/testfile_VS2005.vcproj
old mode 100755
new mode 100644
diff --git a/VisualC/tests/testgamma/testgamma_VS2005.vcproj b/VisualC/tests/testgamma/testgamma_VS2005.vcproj
old mode 100755
new mode 100644
diff --git a/VisualC/tests/testgl/testgl_VS2005.vcproj b/VisualC/tests/testgl/testgl_VS2005.vcproj
old mode 100755
new mode 100644
diff --git a/VisualC/tests/testgl2/testgl2_VS2005.vcproj b/VisualC/tests/testgl2/testgl2_VS2005.vcproj
old mode 100755
new mode 100644
diff --git a/VisualC/tests/testjoystick/testjoystick_VS2005.vcproj b/VisualC/tests/testjoystick/testjoystick_VS2005.vcproj
old mode 100755
new mode 100644
diff --git a/VisualC/tests/testoverlay/testoverlay_VS2005.vcproj b/VisualC/tests/testoverlay/testoverlay_VS2005.vcproj
old mode 100755
new mode 100644
diff --git a/VisualC/tests/testoverlay2/testoverlay2_VS2005.vcproj b/VisualC/tests/testoverlay2/testoverlay2_VS2005.vcproj
old mode 100755
new mode 100644
diff --git a/VisualC/tests/testpalette/testpalette_VS2005.vcproj b/VisualC/tests/testpalette/testpalette_VS2005.vcproj
old mode 100755
new mode 100644
diff --git a/VisualC/tests/testplatform/testplatform_VS2005.vcproj b/VisualC/tests/testplatform/testplatform_VS2005.vcproj
old mode 100755
new mode 100644
diff --git a/VisualC/tests/testpower/testpower_VS2005.vcproj b/VisualC/tests/testpower/testpower_VS2005.vcproj
old mode 100755
new mode 100644
diff --git a/VisualC/tests/testsprite/testsprite_VS2005.vcproj b/VisualC/tests/testsprite/testsprite_VS2005.vcproj
old mode 100755
new mode 100644
diff --git a/VisualC/tests/testsprite2/testsprite2_VS2005.vcproj b/VisualC/tests/testsprite2/testsprite2_VS2005.vcproj
old mode 100755
new mode 100644
diff --git a/VisualC/tests/testvidinfo/testvidinfo_VS2005.vcproj b/VisualC/tests/testvidinfo/testvidinfo_VS2005.vcproj
old mode 100755
new mode 100644
diff --git a/VisualC/tests/testwin/testwin_VS2005.vcproj b/VisualC/tests/testwin/testwin_VS2005.vcproj
old mode 100755
new mode 100644
diff --git a/VisualC/tests/testwm/testwm_VS2005.vcproj b/VisualC/tests/testwm/testwm_VS2005.vcproj
old mode 100755
new mode 100644
diff --git a/include/SDL_stdinc.h b/include/SDL_stdinc.h
index 82d21a5af..b3328b154 100644
--- a/include/SDL_stdinc.h
+++ b/include/SDL_stdinc.h
@@ -472,6 +472,19 @@ extern DECLSPEC size_t SDLCALL SDL_strlen(const char *string);
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 @@ extern DECLSPEC size_t SDLCALL SDL_strlcpy(char *dst, const char *src,
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
diff --git a/src/events/SDL_keyboard.c b/src/events/SDL_keyboard.c
index 23c85d70d..cdee58f88 100644
--- a/src/events/SDL_keyboard.c
+++ b/src/events/SDL_keyboard.c
@@ -778,7 +778,7 @@ SDL_SendKeyboardText(const char *text)
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 @@ SDL_SendEditingText(const char *text, int start, int length)
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);
diff --git a/src/haptic/nds/SDL_syshaptic.c b/src/haptic/nds/SDL_syshaptic.c
index 6cf9518b2..7ba3c90e5 100644
--- a/src/haptic/nds/SDL_syshaptic.c
+++ b/src/haptic/nds/SDL_syshaptic.c
@@ -43,35 +43,35 @@ typedef struct
} 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 @@ NDS_EZF_ChipReset()
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)
diff --git a/src/joystick/nds/SDL_sysjoystick.c b/src/joystick/nds/SDL_sysjoystick.c
index cdfbdacac..e885a5da0 100644
--- a/src/joystick/nds/SDL_sysjoystick.c
+++ b/src/joystick/nds/SDL_sysjoystick.c
@@ -45,7 +45,7 @@ int
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 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick)
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 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
{
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 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
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
diff --git a/src/stdlib/SDL_string.c b/src/stdlib/SDL_string.c
index d70f8666a..02f086773 100644
--- a/src/stdlib/SDL_string.c
+++ b/src/stdlib/SDL_string.c
@@ -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 @@ SDL_wcslen(const wchar_t * string)
}
#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 @@ SDL_strlcpy(char *dst, const char *src, size_t maxlen)
}
#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)
diff --git a/src/video/win32/SDL_win32events.c b/src/video/win32/SDL_win32events.c
old mode 100755
new mode 100644
index 3eae9bbe9..272cedcad
--- a/src/video/win32/SDL_win32events.c
+++ b/src/video/win32/SDL_win32events.c
@@ -139,6 +139,8 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
}
#endif
+ if (IME_HandleMessage(hwnd, msg, wParam, &lParam, data->videodata))
+ return 0;
switch (msg) {
@@ -605,7 +607,7 @@ SDL_RegisterApp(char *name, Uint32 style, void *hInst)
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)) {
diff --git a/src/video/win32/SDL_win32keyboard.c b/src/video/win32/SDL_win32keyboard.c
index 5a7523b02..597cc5347 100644
--- a/src/video/win32/SDL_win32keyboard.c
+++ b/src/video/win32/SDL_win32keyboard.c
@@ -26,6 +26,14 @@
#include "../../events/SDL_keyboard_c.h"
#include "../../events/scancodes_win32.h"
+#include
+#include
+
+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 @@ WIN_InitKeyboard(_THIS)
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 @@ WIN_UpdateKeymap()
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: */
diff --git a/src/video/win32/SDL_win32keyboard.h b/src/video/win32/SDL_win32keyboard.h
index c67410a63..670730bba 100644
--- a/src/video/win32/SDL_win32keyboard.h
+++ b/src/video/win32/SDL_win32keyboard.h
@@ -31,6 +31,12 @@ extern void WIN_InitKeyboard(_THIS);
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: */
diff --git a/src/video/win32/SDL_win32video.c b/src/video/win32/SDL_win32video.c
index af21a2ff3..b82a1cd7d 100644
--- a/src/video/win32/SDL_win32video.c
+++ b/src/video/win32/SDL_win32video.c
@@ -191,6 +191,9 @@ WIN_CreateDevice(int devindex)
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;
diff --git a/src/video/win32/SDL_win32video.h b/src/video/win32/SDL_win32video.h
index 2f26320a4..2f1f7f75b 100644
--- a/src/video/win32/SDL_win32video.h
+++ b/src/video/win32/SDL_win32video.h
@@ -42,6 +42,8 @@
#include
+#include
+
#if SDL_VIDEO_RENDER_D3D
//#include
#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 @@ enum { RENDER_NONE, RENDER_D3D, RENDER_DDRAW, RENDER_GDI, RENDER_GAPI, RENDER_RA
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 @@ typedef struct SDL_VideoData
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 */
diff --git a/src/video/win32/SDL_win32window.c b/src/video/win32/SDL_win32window.c
index eb579152c..9a9a52df1 100644
--- a/src/video/win32/SDL_win32window.c
+++ b/src/video/win32/SDL_win32window.c
@@ -77,10 +77,12 @@ SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, SDL_bool created)
/* 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 */
{
diff --git a/test/testime.c b/test/testime.c
index bae74000f..0f9ba51e8 100644
--- a/test/testime.c
+++ b/test/testime.c
@@ -25,7 +25,49 @@ TTF_Font *font;
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 @@ void InitInput()
text[0] = 0;
markedRect = textRect;
- markedText = NULL;
+ markedText[0] = 0;
SDL_StartTextInput();
}
@@ -180,9 +222,22 @@ void Redraw()
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 @@ void Redraw()
underlineRect.h = 2;
underlineRect.w = w;
- cursorRect.x += w + 1;
-
SDL_FillRect(screen, &underlineRect, lineColor);
}
@@ -295,13 +348,13 @@ int main(int argc, char *argv[])
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 @@ int main(int argc, char *argv[])
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;