# HG changeset patch # User Sam Lantinga # Date 1282505967 25200 # Node ID 518d1679d2d0399e9308680f49c6aa13b42990fe # Parent 833a225613e22cbce8bf0f53321c45cabe64a2dd# Parent bb2e32f5a556e26a3087cdb1e0039859beb6542d Merged Daniel's Google Summer of Code work from SDL-gsoc2010_IME diff -r 833a225613e2 -r 518d1679d2d0 EXCLUDE/GLIMM/GLIMM.sln --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLIMM/GLIMM.sln Sun Aug 22 12:39:27 2010 -0700 @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GLIMM", "GLIMM.vcproj", "{F21B830F-20A9-4473-B67A-21D1743C6E19}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F21B830F-20A9-4473-B67A-21D1743C6E19}.Debug|Win32.ActiveCfg = Debug|Win32 + {F21B830F-20A9-4473-B67A-21D1743C6E19}.Debug|Win32.Build.0 = Debug|Win32 + {F21B830F-20A9-4473-B67A-21D1743C6E19}.Release|Win32.ActiveCfg = Release|Win32 + {F21B830F-20A9-4473-B67A-21D1743C6E19}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff -r 833a225613e2 -r 518d1679d2d0 EXCLUDE/GLIMM/GLIMM.vcproj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLIMM/GLIMM.vcproj Sun Aug 22 12:39:27 2010 -0700 @@ -0,0 +1,233 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r 833a225613e2 -r 518d1679d2d0 EXCLUDE/GLIMM/include/App.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLIMM/include/App.hpp Sun Aug 22 12:39:27 2010 -0700 @@ -0,0 +1,37 @@ +#ifndef APP_HPP +#define APP_HPP + +#include "Window.hpp" + +class App : public Window_Listener +{ +public: + App(); + virtual ~App(); + + void Initialize(); + void Finalize(); + + void Run(); + + virtual void On_Close(); + virtual void On_Key_Down(int Key); + virtual void On_Key_Up(int Key); + virtual void On_Char(unsigned int Char); + virtual void On_Resized(unsigned int Width, unsigned int Height); + virtual void On_Mouse_Button_Down(Mouse_Button Button); + +private: + void Update(); + void Draw(); + + static const int Width = 800; + static const int Height = 600; + static const int Bits_Per_Pixel = 32; + static const bool Fullscreen = true; + + Window my_Window; + bool my_Done; +}; + +#endif diff -r 833a225613e2 -r 518d1679d2d0 EXCLUDE/GLIMM/include/IMM.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLIMM/include/IMM.hpp Sun Aug 22 12:39:27 2010 -0700 @@ -0,0 +1,41 @@ +#ifndef IMM_HPP +#define IMM_HPP + +#define WIN32_LEAN_AND_MEAN +#include +#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 -r 833a225613e2 -r 518d1679d2d0 EXCLUDE/GLIMM/include/Video_Mode.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLIMM/include/Video_Mode.hpp Sun Aug 22 12:39:27 2010 -0700 @@ -0,0 +1,30 @@ +#ifndef VIDEO_MODE_HPP +#define VIDEO_MODE_HPP + +#include + +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 -r 833a225613e2 -r 518d1679d2d0 EXCLUDE/GLIMM/include/Window.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLIMM/include/Window.hpp Sun Aug 22 12:39:27 2010 -0700 @@ -0,0 +1,63 @@ +#ifndef WINDOW_HPP +#define WINDOW_HPP + +#include + +#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 -r 833a225613e2 -r 518d1679d2d0 EXCLUDE/GLIMM/include/Window_Listener.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLIMM/include/Window_Listener.hpp Sun Aug 22 12:39:27 2010 -0700 @@ -0,0 +1,23 @@ +#ifndef WINDOW_LISTENER_HPP +#define WINDOW_LISTENER_HPP + +enum Mouse_Button +{ + Mouse_Button_Left, + Mouse_Button_Right +}; + +class Window_Listener +{ +public: + virtual void On_Close(){} + virtual void On_Key_Down(int Key){} + virtual void On_Key_Up(int Key){} + virtual void On_Char(unsigned int Char){} + virtual void On_Resized(unsigned int Width, unsigned int Height){} + virtual void On_Mouse_Button_Down(Mouse_Button Button){} + virtual void On_Mouse_Button_Up(Mouse_Button Button){} + +}; + +#endif diff -r 833a225613e2 -r 518d1679d2d0 EXCLUDE/GLIMM/src/App.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLIMM/src/App.cpp Sun Aug 22 12:39:27 2010 -0700 @@ -0,0 +1,113 @@ +#include "App.hpp" +#include +#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 -r 833a225613e2 -r 518d1679d2d0 EXCLUDE/GLIMM/src/IMM.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLIMM/src/IMM.cpp Sun Aug 22 12:39:27 2010 -0700 @@ -0,0 +1,237 @@ +#include "IMM.hpp" +#include + +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 -r 833a225613e2 -r 518d1679d2d0 EXCLUDE/GLIMM/src/Main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLIMM/src/Main.cpp Sun Aug 22 12:39:27 2010 -0700 @@ -0,0 +1,24 @@ +#include "App.hpp" +#include + +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 -r 833a225613e2 -r 518d1679d2d0 EXCLUDE/GLIMM/src/Video_Mode.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLIMM/src/Video_Mode.cpp Sun Aug 22 12:39:27 2010 -0700 @@ -0,0 +1,100 @@ +#include "Video_Mode.hpp" +#include +#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 -r 833a225613e2 -r 518d1679d2d0 EXCLUDE/GLIMM/src/Window.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLIMM/src/Window.cpp Sun Aug 22 12:39:27 2010 -0700 @@ -0,0 +1,317 @@ +#include "Window.hpp" +#include + +#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 -r 833a225613e2 -r 518d1679d2d0 EXCLUDE/GLTSF/GLTSF.sln --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLTSF/GLTSF.sln Sun Aug 22 12:39:27 2010 -0700 @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GLTSF", "GLTSF.vcxproj", "{790D58BA-E5F6-4286-A9C6-0DC28779789D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {790D58BA-E5F6-4286-A9C6-0DC28779789D}.Debug|Win32.ActiveCfg = Debug|Win32 + {790D58BA-E5F6-4286-A9C6-0DC28779789D}.Debug|Win32.Build.0 = Debug|Win32 + {790D58BA-E5F6-4286-A9C6-0DC28779789D}.Release|Win32.ActiveCfg = Release|Win32 + {790D58BA-E5F6-4286-A9C6-0DC28779789D}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff -r 833a225613e2 -r 518d1679d2d0 EXCLUDE/GLTSF/GLTSF.vcproj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLTSF/GLTSF.vcproj Sun Aug 22 12:39:27 2010 -0700 @@ -0,0 +1,231 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r 833a225613e2 -r 518d1679d2d0 EXCLUDE/GLTSF/GLTSF.vcxproj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLTSF/GLTSF.vcxproj Sun Aug 22 12:39:27 2010 -0700 @@ -0,0 +1,99 @@ + + + + + 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 -r 833a225613e2 -r 518d1679d2d0 EXCLUDE/GLTSF/GLTSF.vcxproj.filters --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLTSF/GLTSF.vcxproj.filters Sun Aug 22 12:39:27 2010 -0700 @@ -0,0 +1,51 @@ + + + + + {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 -r 833a225613e2 -r 518d1679d2d0 EXCLUDE/GLTSF/GLTSF_vs2008.sln --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLTSF/GLTSF_vs2008.sln Sun Aug 22 12:39:27 2010 -0700 @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GLTSF", "GLTSF.vcproj", "{FC8A9A48-6667-4BDE-8E9B-5859408AEE83}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FC8A9A48-6667-4BDE-8E9B-5859408AEE83}.Debug|Win32.ActiveCfg = Debug|Win32 + {FC8A9A48-6667-4BDE-8E9B-5859408AEE83}.Debug|Win32.Build.0 = Debug|Win32 + {FC8A9A48-6667-4BDE-8E9B-5859408AEE83}.Release|Win32.ActiveCfg = Release|Win32 + {FC8A9A48-6667-4BDE-8E9B-5859408AEE83}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff -r 833a225613e2 -r 518d1679d2d0 EXCLUDE/GLTSF/include/App.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLTSF/include/App.hpp Sun Aug 22 12:39:27 2010 -0700 @@ -0,0 +1,36 @@ +#ifndef APP_HPP +#define APP_HPP + +#include "Window.hpp" + +class App : public Window_Listener +{ +public: + App(); + virtual ~App(); + + void Initialize(); + void Finalize(); + + void Run(); + + virtual void On_Close(); + virtual void On_Key_Down(int Key); + virtual void On_Key_Up(int Key); + virtual void On_Char(unsigned int Char); + virtual void On_Resized(unsigned int Width, unsigned int Height); + +private: + void Update(); + void Draw(); + + static const int Width = 800; + static const int Height = 600; + static const int Bits_Per_Pixel = 32; + static const bool Fullscreen = true; + + Window my_Window; + bool my_Done; +}; + +#endif diff -r 833a225613e2 -r 518d1679d2d0 EXCLUDE/GLTSF/include/TSF.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLTSF/include/TSF.hpp Sun Aug 22 12:39:27 2010 -0700 @@ -0,0 +1,83 @@ +#ifndef TSF_HPP +#define TSF_HPP + +#include +#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 -r 833a225613e2 -r 518d1679d2d0 EXCLUDE/GLTSF/include/Video_Mode.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLTSF/include/Video_Mode.hpp Sun Aug 22 12:39:27 2010 -0700 @@ -0,0 +1,30 @@ +#ifndef VIDEO_MODE_HPP +#define VIDEO_MODE_HPP + +#include + +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 -r 833a225613e2 -r 518d1679d2d0 EXCLUDE/GLTSF/include/Window.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLTSF/include/Window.hpp Sun Aug 22 12:39:27 2010 -0700 @@ -0,0 +1,59 @@ +#ifndef WINDOW_HPP +#define WINDOW_HPP + +#include + +#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 -r 833a225613e2 -r 518d1679d2d0 EXCLUDE/GLTSF/include/Window_Listener.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLTSF/include/Window_Listener.hpp Sun Aug 22 12:39:27 2010 -0700 @@ -0,0 +1,14 @@ +#ifndef WINDOW_LISTENER_HPP +#define WINDOW_LISTENER_HPP + +class Window_Listener +{ +public: + virtual void On_Close(){} + virtual void On_Key_Down(int Key){} + virtual void On_Key_Up(int Key){} + virtual void On_Char(unsigned int Char){} + virtual void On_Resized(unsigned int Width, unsigned int Height){} +}; + +#endif diff -r 833a225613e2 -r 518d1679d2d0 EXCLUDE/GLTSF/src/App.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLTSF/src/App.cpp Sun Aug 22 12:39:27 2010 -0700 @@ -0,0 +1,105 @@ +#include "App.hpp" +#include "TSF.hpp" +#include +#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 -r 833a225613e2 -r 518d1679d2d0 EXCLUDE/GLTSF/src/Main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLTSF/src/Main.cpp Sun Aug 22 12:39:27 2010 -0700 @@ -0,0 +1,24 @@ +#include "App.hpp" +#include + +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 -r 833a225613e2 -r 518d1679d2d0 EXCLUDE/GLTSF/src/TSF.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLTSF/src/TSF.cpp Sun Aug 22 12:39:27 2010 -0700 @@ -0,0 +1,360 @@ +#include "TSF.hpp" +#include + +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 -r 833a225613e2 -r 518d1679d2d0 EXCLUDE/GLTSF/src/Video_Mode.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLTSF/src/Video_Mode.cpp Sun Aug 22 12:39:27 2010 -0700 @@ -0,0 +1,100 @@ +#include "Video_Mode.hpp" +#include +#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 -r 833a225613e2 -r 518d1679d2d0 EXCLUDE/GLTSF/src/Window.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EXCLUDE/GLTSF/src/Window.cpp Sun Aug 22 12:39:27 2010 -0700 @@ -0,0 +1,281 @@ +#include "Window.hpp" +#include + +#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 -r 833a225613e2 -r 518d1679d2d0 VisualC/tests/automated/automated_VS2008.vcproj diff -r 833a225613e2 -r 518d1679d2d0 VisualC/tests/checkkeys/checkkeys_VS2005.vcproj diff -r 833a225613e2 -r 518d1679d2d0 VisualC/tests/graywin/graywin_VS2005.vcproj diff -r 833a225613e2 -r 518d1679d2d0 VisualC/tests/loopwave/loopwave_VS2005.vcproj diff -r 833a225613e2 -r 518d1679d2d0 VisualC/tests/testalpha/testalpha_VS2005.vcproj diff -r 833a225613e2 -r 518d1679d2d0 VisualC/tests/testdraw2/testdraw2_VS2005.vcproj diff -r 833a225613e2 -r 518d1679d2d0 VisualC/tests/testfile/testfile_VS2005.vcproj diff -r 833a225613e2 -r 518d1679d2d0 VisualC/tests/testgamma/testgamma_VS2005.vcproj diff -r 833a225613e2 -r 518d1679d2d0 VisualC/tests/testgl/testgl_VS2005.vcproj diff -r 833a225613e2 -r 518d1679d2d0 VisualC/tests/testgl2/testgl2_VS2005.vcproj diff -r 833a225613e2 -r 518d1679d2d0 VisualC/tests/testjoystick/testjoystick_VS2005.vcproj diff -r 833a225613e2 -r 518d1679d2d0 VisualC/tests/testoverlay/testoverlay_VS2005.vcproj diff -r 833a225613e2 -r 518d1679d2d0 VisualC/tests/testoverlay2/testoverlay2_VS2005.vcproj diff -r 833a225613e2 -r 518d1679d2d0 VisualC/tests/testpalette/testpalette_VS2005.vcproj diff -r 833a225613e2 -r 518d1679d2d0 VisualC/tests/testplatform/testplatform_VS2005.vcproj diff -r 833a225613e2 -r 518d1679d2d0 VisualC/tests/testpower/testpower_VS2005.vcproj diff -r 833a225613e2 -r 518d1679d2d0 VisualC/tests/testsprite/testsprite_VS2005.vcproj diff -r 833a225613e2 -r 518d1679d2d0 VisualC/tests/testsprite2/testsprite2_VS2005.vcproj diff -r 833a225613e2 -r 518d1679d2d0 VisualC/tests/testvidinfo/testvidinfo_VS2005.vcproj diff -r 833a225613e2 -r 518d1679d2d0 VisualC/tests/testwin/testwin_VS2005.vcproj diff -r 833a225613e2 -r 518d1679d2d0 VisualC/tests/testwm/testwm_VS2005.vcproj diff -r 833a225613e2 -r 518d1679d2d0 include/SDL_keyboard.h diff -r 833a225613e2 -r 518d1679d2d0 include/SDL_stdinc.h --- a/include/SDL_stdinc.h Sun Aug 22 12:35:34 2010 -0700 +++ b/include/SDL_stdinc.h Sun Aug 22 12:39:27 2010 -0700 @@ -472,6 +472,19 @@ extern DECLSPEC size_t SDLCALL SDL_wcslen(const wchar_t * string); #endif +#ifdef HAVE_WCSLCPY +#define SDL_wcslcpy wcslcpy +#else +extern DECLSPEC size_t SDLCALL SDL_wcslcpy(wchar_t *dst, const wchar_t *src, size_t maxlen); +#endif + +#ifdef HAVE_WCSLCAT +#define SDL_wcslcat wcslcat +#else +extern DECLSPEC size_t SDLCALL SDL_wcslcat(wchar_t *dst, const wchar_t *src, size_t maxlen); +#endif + + #ifdef HAVE_STRLCPY #define SDL_strlcpy strlcpy #else @@ -479,6 +492,9 @@ size_t maxlen); #endif +extern DECLSPEC size_t SDLCALL SDL_utf8strlcpy(char *dst, const char *src, + size_t dst_bytes); + #ifdef HAVE_STRLCAT #define SDL_strlcat strlcat #else diff -r 833a225613e2 -r 518d1679d2d0 src/SDL_compat.c diff -r 833a225613e2 -r 518d1679d2d0 src/events/SDL_keyboard.c --- a/src/events/SDL_keyboard.c Sun Aug 22 12:35:34 2010 -0700 +++ b/src/events/SDL_keyboard.c Sun Aug 22 12:39:27 2010 -0700 @@ -778,7 +778,7 @@ SDL_Event event; event.text.type = SDL_TEXTINPUT; event.text.windowID = keyboard->focus ? keyboard->focus->id : 0; - SDL_strlcpy(event.text.text, text, SDL_arraysize(event.text.text)); + SDL_utf8strlcpy(event.text.text, text, SDL_arraysize(event.text.text)); event.text.windowID = keyboard->focus ? keyboard->focus->id : 0; posted = (SDL_PushEvent(&event) > 0); } @@ -799,7 +799,7 @@ event.edit.windowID = keyboard->focus ? keyboard->focus->id : 0; event.edit.start = start; event.edit.length = length; - SDL_strlcpy(event.edit.text, text, SDL_arraysize(event.edit.text)); + SDL_utf8strlcpy(event.edit.text, text, SDL_arraysize(event.edit.text)); posted = (SDL_PushEvent(&event) > 0); } return (posted); diff -r 833a225613e2 -r 518d1679d2d0 src/haptic/nds/SDL_syshaptic.c --- a/src/haptic/nds/SDL_syshaptic.c Sun Aug 22 12:35:34 2010 -0700 +++ b/src/haptic/nds/SDL_syshaptic.c Sun Aug 22 12:39:27 2010 -0700 @@ -43,35 +43,35 @@ } NDS_HapticData; - void -NDS_EZF_OpenNorWrite() +void +NDS_EZF_OpenNorWrite() { - GBA_BUS[0x0FF0000] = 0xD200; - GBA_BUS[0x0000000] = 0x1500; - GBA_BUS[0x0010000] = 0xD200; - GBA_BUS[0x0020000] = 0x1500; - GBA_BUS[0x0E20000] = 0x1500; - GBA_BUS[0x0FE0000] = 0x1500; - } void + GBA_BUS[0x0FF0000] = 0xD200; + GBA_BUS[0x0000000] = 0x1500; + GBA_BUS[0x0010000] = 0xD200; + GBA_BUS[0x0020000] = 0x1500; + GBA_BUS[0x0E20000] = 0x1500; + GBA_BUS[0x0FE0000] = 0x1500; +} void -NDS_EZF_CloseNorWrite() +NDS_EZF_CloseNorWrite() { - GBA_BUS[0x0FF0000] = 0xD200; - GBA_BUS[0x0000000] = 0x1500; - GBA_BUS[0x0010000] = 0xD200; - GBA_BUS[0x0020000] = 0x1500; - GBA_BUS[0x0E20000] = 0xD200; - GBA_BUS[0x0FE0000] = 0x1500; - } + GBA_BUS[0x0FF0000] = 0xD200; + GBA_BUS[0x0000000] = 0x1500; + GBA_BUS[0x0010000] = 0xD200; + GBA_BUS[0x0020000] = 0x1500; + GBA_BUS[0x0E20000] = 0xD200; + GBA_BUS[0x0FE0000] = 0x1500; +} void NDS_EZF_ChipReset() { - GBA_BUS[0x0000] = 0x00F0; - GBA_BUS[0x1000] = 0x00F0; -} uint32 NDS_EZF_IsPresent() + GBA_BUS[0x0000] = 0x00F0; + GBA_BUS[0x1000] = 0x00F0; +} uint32 NDS_EZF_IsPresent() { - vuint16 id1, id2; + vuint16 id1, id2; NDS_EZF_OpenNorWrite(); @@ -81,35 +81,35 @@ GBA_BUS[0x1555] = 0x00AA; GBA_BUS[0x12AA] = 0x0055; GBA_BUS[0x1555] = 0x0090; - id1 = GBA_BUS[0x0001]; - id2 = GBA_BUS[0x1001]; - if ((id1 != 0x227E) || (id2 != 0x227E)) { + id1 = GBA_BUS[0x0001]; + id2 = GBA_BUS[0x1001]; + if ((id1 != 0x227E) || (id2 != 0x227E)) { NDS_EZF_CloseNorWrite(); - return 0; + return 0; } - id1 = GBA_BUS[0x000E]; - id2 = GBA_BUS[0x100E]; + id1 = GBA_BUS[0x000E]; + id2 = GBA_BUS[0x100E]; NDS_EZF_CloseNorWrite(); - if (id1 == 0x2218 && id2 == 0x2218) { - return 1; + if (id1 == 0x2218 && id2 == 0x2218) { + return 1; } - return 0; - } - void -NDS_EZF_SetShake(u8 pos) + return 0; +} +void +NDS_EZF_SetShake(u8 pos) { u16 data = ((pos % 3) | 0x00F0); - GBA_BUS[0x0FF0000] = 0xD200; - GBA_BUS[0x0000000] = 0x1500; - GBA_BUS[0x0010000] = 0xD200; - GBA_BUS[0x0020000] = 0x1500; - GBA_BUS[0x0F10000] = data; - GBA_BUS[0x0FE0000] = 0x1500; + GBA_BUS[0x0FF0000] = 0xD200; + GBA_BUS[0x0000000] = 0x1500; + GBA_BUS[0x0010000] = 0xD200; + GBA_BUS[0x0020000] = 0x1500; + GBA_BUS[0x0F10000] = data; + GBA_BUS[0x0FE0000] = 0x1500; GBA_BUS[0] = 0x0000; /* write any value for vibration. */ GBA_BUS[0] = 0x0002; - } +} static int SDL_SYS_LogicError(void) diff -r 833a225613e2 -r 518d1679d2d0 src/joystick/nds/SDL_sysjoystick.c --- a/src/joystick/nds/SDL_sysjoystick.c Sun Aug 22 12:35:34 2010 -0700 +++ b/src/joystick/nds/SDL_sysjoystick.c Sun Aug 22 12:39:27 2010 -0700 @@ -45,7 +45,7 @@ SDL_SYS_JoystickInit(void) { SDL_numjoysticks = 1; - return (1); + return (1); } /* Function to get the device-dependent name of a joystick */ @@ -73,7 +73,7 @@ return 0; } - + /* Function to update the state of a joystick - called as a device poll. * This function shouldn't update the joystick structure directly, * but instead should call SDL_PrivateJoystick*() to deliver events @@ -84,8 +84,8 @@ { u32 keysd, keysu; int magnitude = 16384; - - /*scanKeys(); - this is done in PumpEvents, because touch uses it too */ + + /*scanKeys(); - this is done in PumpEvents, because touch uses it too */ keysd = keysDown(); keysu = keysUp(); @@ -101,61 +101,61 @@ if ((keysd & KEY_RIGHT)) { SDL_PrivateJoystickAxis(joystick, 0, magnitude); } - if ((keysu & (KEY_UP | KEY_DOWN))) { + if ((keysu & (KEY_UP | KEY_DOWN))) { SDL_PrivateJoystickAxis(joystick, 1, 0); } - if ((keysu & (KEY_LEFT | KEY_RIGHT))) { + if ((keysu & (KEY_LEFT | KEY_RIGHT))) { SDL_PrivateJoystickAxis(joystick, 0, 0); } - if ((keysd & KEY_A)) { + if ((keysd & KEY_A)) { SDL_PrivateJoystickButton(joystick, 0, SDL_PRESSED); } - if ((keysd & KEY_B)) { + if ((keysd & KEY_B)) { SDL_PrivateJoystickButton(joystick, 1, SDL_PRESSED); } - if ((keysd & KEY_X)) { + if ((keysd & KEY_X)) { SDL_PrivateJoystickButton(joystick, 2, SDL_PRESSED); } - if ((keysd & KEY_Y)) { + if ((keysd & KEY_Y)) { SDL_PrivateJoystickButton(joystick, 3, SDL_PRESSED); } - if ((keysd & KEY_L)) { + if ((keysd & KEY_L)) { SDL_PrivateJoystickButton(joystick, 4, SDL_PRESSED); } - if ((keysd & KEY_R)) { + if ((keysd & KEY_R)) { SDL_PrivateJoystickButton(joystick, 5, SDL_PRESSED); } - if ((keysd & KEY_SELECT)) { + if ((keysd & KEY_SELECT)) { SDL_PrivateJoystickButton(joystick, 6, SDL_PRESSED); } - if ((keysd & KEY_START)) { + if ((keysd & KEY_START)) { SDL_PrivateJoystickButton(joystick, 7, SDL_PRESSED); } - if ((keysu & KEY_A)) { + if ((keysu & KEY_A)) { SDL_PrivateJoystickButton(joystick, 0, SDL_RELEASED); } - if ((keysu & KEY_B)) { + if ((keysu & KEY_B)) { SDL_PrivateJoystickButton(joystick, 1, SDL_RELEASED); } - if ((keysu & KEY_X)) { + if ((keysu & KEY_X)) { SDL_PrivateJoystickButton(joystick, 2, SDL_RELEASED); } - if ((keysu & KEY_Y)) { + if ((keysu & KEY_Y)) { SDL_PrivateJoystickButton(joystick, 3, SDL_RELEASED); } - if ((keysu & KEY_L)) { + if ((keysu & KEY_L)) { SDL_PrivateJoystickButton(joystick, 4, SDL_RELEASED); } - if ((keysu & KEY_R)) { + if ((keysu & KEY_R)) { SDL_PrivateJoystickButton(joystick, 5, SDL_RELEASED); } - if ((keysu & KEY_SELECT)) { + if ((keysu & KEY_SELECT)) { SDL_PrivateJoystickButton(joystick, 6, SDL_RELEASED); } - if ((keysu & KEY_START)) { + if ((keysu & KEY_START)) { SDL_PrivateJoystickButton(joystick, 7, SDL_RELEASED); } - } +} /* Function to close a joystick after use */ void diff -r 833a225613e2 -r 518d1679d2d0 src/stdlib/SDL_string.c --- a/src/stdlib/SDL_string.c Sun Aug 22 12:35:34 2010 -0700 +++ b/src/stdlib/SDL_string.c Sun Aug 22 12:39:27 2010 -0700 @@ -29,6 +29,21 @@ #define SDL_isupperhex(X) (((X) >= 'A') && ((X) <= 'F')) #define SDL_islowerhex(X) (((X) >= 'a') && ((X) <= 'f')) +#define UTF8_IsLeadByte(c) ((c) >= 0xC0 && (c) <= 0xF4) +#define UTF8_IsTrailingByte(c) ((c) >= 0x80 && (c) <= 0xBF) + +int UTF8_TrailingBytes(unsigned char c) +{ + if (c >= 0xC0 && c<= 0xDF) + return 1; + else if (c >= 0xE0 && c <= 0xEF) + return 2; + else if (c >= 0xF0 && c <= 0xF4) + return 3; + else + return 0; +} + #if !defined(HAVE_SSCANF) || !defined(HAVE_STRTOL) static size_t SDL_ScanLong(const char *text, int radix, long *valuep) @@ -348,6 +363,33 @@ } #endif +#ifndef HAVE_WCSLCPY +size_t +SDL_wcslcpy(wchar_t *dst, const wchar_t *src, size_t maxlen) +{ + size_t srclen = SDL_wcslen(src); + if (maxlen > 0) { + size_t len = SDL_min(srclen, maxlen - 1); + SDL_memcpy(dst, src, len * sizeof(wchar_t)); + dst[len] = '\0'; + } + return srclen; +} +#endif + +#ifndef HAVE_WCSLCAT +size_t +SDL_wcslcat(wchar_t *dst, const wchar_t *src, size_t maxlen) +{ + size_t dstlen = SDL_wcslen(dst); + size_t srclen = SDL_wcslen(src); + if (dstlen < maxlen) { + SDL_wcslcpy(dst + dstlen, src, maxlen - dstlen); + } + return dstlen + srclen; +} +#endif + #ifndef HAVE_STRLCPY size_t SDL_strlcpy(char *dst, const char *src, size_t maxlen) @@ -362,6 +404,38 @@ } #endif +size_t SDL_utf8strlcpy(char *dst, const char *src, size_t dst_bytes) +{ + size_t src_bytes = SDL_strlen(src); + size_t bytes = SDL_min(src_bytes, dst_bytes - 1); + int i = 0; + char trailing_bytes = 0; + if (bytes) + { + unsigned char c = (unsigned char)src[bytes - 1]; + if (UTF8_IsLeadByte(c)) + --bytes; + else if (UTF8_IsTrailingByte(c)) + { + for (i = bytes - 1; i != 0; --i) + { + c = (unsigned char)src[i]; + trailing_bytes = UTF8_TrailingBytes(c); + if (trailing_bytes) + { + if (bytes - i != trailing_bytes + 1) + bytes = i; + + break; + } + } + } + SDL_memcpy(dst, src, bytes); + } + dst[bytes] = '\0'; + return bytes; +} + #ifndef HAVE_STRLCAT size_t SDL_strlcat(char *dst, const char *src, size_t maxlen) diff -r 833a225613e2 -r 518d1679d2d0 src/video/SDL_sysvideo.h diff -r 833a225613e2 -r 518d1679d2d0 src/video/SDL_video.c diff -r 833a225613e2 -r 518d1679d2d0 src/video/win32/SDL_win32events.c --- a/src/video/win32/SDL_win32events.c Sun Aug 22 12:35:34 2010 -0700 +++ b/src/video/win32/SDL_win32events.c Sun Aug 22 12:39:27 2010 -0700 @@ -139,6 +139,8 @@ } #endif + if (IME_HandleMessage(hwnd, msg, wParam, &lParam, data->videodata)) + return 0; switch (msg) { @@ -605,7 +607,7 @@ class.hbrBackground = NULL; class.hInstance = SDL_Instance; class.style = SDL_Appstyle; - class.lpfnWndProc = DefWindowProc; + class.lpfnWndProc = WIN_WindowProc; class.cbWndExtra = 0; class.cbClsExtra = 0; if (!RegisterClass(&class)) { diff -r 833a225613e2 -r 518d1679d2d0 src/video/win32/SDL_win32keyboard.c --- a/src/video/win32/SDL_win32keyboard.c Sun Aug 22 12:35:34 2010 -0700 +++ b/src/video/win32/SDL_win32keyboard.c Sun Aug 22 12:39:27 2010 -0700 @@ -26,6 +26,14 @@ #include "../../events/SDL_keyboard_c.h" #include "../../events/scancodes_win32.h" +#include +#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 @@ data->key_layout = win32_scancode_table; + data->ime_com_initialized = SDL_FALSE; + data->ime_threadmgr = 0; + data->ime_initialized = SDL_FALSE; + data->ime_enabled = SDL_FALSE; + data->ime_available = SDL_FALSE; + data->ime_hwnd_main = 0; + data->ime_hwnd_current = 0; + data->ime_himc = 0; + data->ime_composition[0] = 0; + data->ime_readingstring[0] = 0; + data->ime_cursor = 0; + data->ime_hkl = 0; + data->ime_himm32 = 0; + data->GetReadingString = 0; + data->ShowReadingWindow = 0; + data->ImmLockIMC = 0; + data->ImmUnlockIMC = 0; + data->ImmLockIMCC = 0; + data->ImmUnlockIMCC = 0; + data->ime_uiless = SDL_FALSE; + data->ime_threadmgrex = 0; + data->ime_uielemsinkcookie = TF_INVALID_COOKIE; + data->ime_alpnsinkcookie = TF_INVALID_COOKIE; + data->ime_openmodesinkcookie = TF_INVALID_COOKIE; + data->ime_convmodesinkcookie = TF_INVALID_COOKIE; + data->ime_uielemsink = 0; + data->ime_ippasink = 0; + WIN_UpdateKeymap(); SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu"); @@ -119,6 +155,851 @@ void WIN_QuitKeyboard(_THIS) { + IME_Quit((SDL_VideoData *)_this->driverdata); +} + +void +WIN_StartTextInput(_THIS) +{ + SDL_Window *window = SDL_GetKeyboardFocus(); + if (window) { + HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; + SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata; + IME_Init(videodata, hwnd); + IME_Enable(videodata, hwnd); + } +} + +void +WIN_StopTextInput(_THIS) +{ + SDL_Window *window = SDL_GetKeyboardFocus(); + if (window) { + HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; + SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata; + IME_Init(videodata, hwnd); + IME_Disable(videodata, hwnd); + } +} + +void +WIN_SetTextInputRect(_THIS, SDL_Rect *rect) +{ + +} + +#define LANG_CHT MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL) +#define LANG_CHS MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED) + +#define MAKEIMEVERSION(major,minor) ((DWORD) (((BYTE)(major) << 24) | ((BYTE)(minor) << 16) )) +#define IMEID_VER(id) ((id) & 0xffff0000) +#define IMEID_LANG(id) ((id) & 0x0000ffff) + +#define CHT_HKL_DAYI ((HKL)0xE0060404) +#define CHT_HKL_NEW_PHONETIC ((HKL)0xE0080404) +#define CHT_HKL_NEW_CHANG_JIE ((HKL)0xE0090404) +#define CHT_HKL_NEW_QUICK ((HKL)0xE00A0404) +#define CHT_HKL_HK_CANTONESE ((HKL)0xE00B0404) +#define CHT_IMEFILENAME1 "TINTLGNT.IME" +#define CHT_IMEFILENAME2 "CINTLGNT.IME" +#define CHT_IMEFILENAME3 "MSTCIPHA.IME" +#define IMEID_CHT_VER42 (LANG_CHT | MAKEIMEVERSION(4, 2)) +#define IMEID_CHT_VER43 (LANG_CHT | MAKEIMEVERSION(4, 3)) +#define IMEID_CHT_VER44 (LANG_CHT | MAKEIMEVERSION(4, 4)) +#define IMEID_CHT_VER50 (LANG_CHT | MAKEIMEVERSION(5, 0)) +#define IMEID_CHT_VER51 (LANG_CHT | MAKEIMEVERSION(5, 1)) +#define IMEID_CHT_VER52 (LANG_CHT | MAKEIMEVERSION(5, 2)) +#define IMEID_CHT_VER60 (LANG_CHT | MAKEIMEVERSION(6, 0)) +#define IMEID_CHT_VER_VISTA (LANG_CHT | MAKEIMEVERSION(7, 0)) + +#define CHS_HKL ((HKL)0xE00E0804) +#define CHS_IMEFILENAME1 "PINTLGNT.IME" +#define CHS_IMEFILENAME2 "MSSCIPYA.IME" +#define IMEID_CHS_VER41 (LANG_CHS | MAKEIMEVERSION(4, 1)) +#define IMEID_CHS_VER42 (LANG_CHS | MAKEIMEVERSION(4, 2)) +#define IMEID_CHS_VER53 (LANG_CHS | MAKEIMEVERSION(5, 3)) + +#define LANG() LOWORD((videodata->ime_hkl)) +#define PRIMLANG() ((WORD)PRIMARYLANGID(LANG())) +#define SUBLANG() SUBLANGID(LANG()) + +static void IME_UpdateInputLocale(SDL_VideoData *videodata); +static void IME_ClearComposition(SDL_VideoData *videodata); +static void IME_SetWindow(SDL_VideoData* videodata, HWND hwnd); +static void IME_SetupAPI(SDL_VideoData *videodata); +static DWORD IME_GetId(SDL_VideoData *videodata, UINT uIndex); +static void IME_SendEditingEvent(SDL_VideoData *videodata); +#define SDL_IsEqualIID(riid1, riid2) SDL_IsEqualGUID(riid1, riid2) +#define SDL_IsEqualGUID(rguid1, rguid2) (!SDL_memcmp(rguid1, rguid2, sizeof(GUID))) + +static SDL_bool UILess_SetupSinks(SDL_VideoData *videodata); +static void UILess_ReleaseSinks(SDL_VideoData *videodata); +static void UILess_EnableUIUpdates(SDL_VideoData *videodata); +static void UILess_DisableUIUpdates(SDL_VideoData *videodata); + +static void +IME_Init(SDL_VideoData *videodata, HWND hwnd) +{ + if (videodata->ime_initialized) + return; + + videodata->ime_hwnd_main = hwnd; + if (SUCCEEDED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) { + videodata->ime_com_initialized = SDL_TRUE; + CoCreateInstance(&CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, &IID_ITfThreadMgr, &videodata->ime_threadmgr); + } + videodata->ime_initialized = SDL_TRUE; + videodata->ime_himm32 = LoadLibraryA("imm32.dll"); + if (!videodata->ime_himm32) { + videodata->ime_available = SDL_FALSE; + return; + } + videodata->ImmLockIMC = (LPINPUTCONTEXT2 (WINAPI *)(HIMC))GetProcAddress(videodata->ime_himm32, "ImmLockIMC"); + videodata->ImmUnlockIMC = (BOOL (WINAPI *)(HIMC))GetProcAddress(videodata->ime_himm32, "ImmUnlockIMC"); + videodata->ImmLockIMCC = (LPVOID (WINAPI *)(HIMCC))GetProcAddress(videodata->ime_himm32, "ImmLockIMCC"); + videodata->ImmUnlockIMCC = (BOOL (WINAPI *)(HIMCC))GetProcAddress(videodata->ime_himm32, "ImmUnlockIMCC"); + + IME_SetWindow(videodata, hwnd); + videodata->ime_himc = ImmGetContext(hwnd); + ImmReleaseContext(hwnd, videodata->ime_himc); + if (!videodata->ime_himc) { + videodata->ime_available = SDL_FALSE; + IME_Disable(videodata, hwnd); + return; + } + videodata->ime_available = SDL_TRUE; + IME_UpdateInputLocale(videodata); + IME_SetupAPI(videodata); + videodata->ime_uiless = UILess_SetupSinks(videodata); + IME_UpdateInputLocale(videodata); + IME_Disable(videodata, hwnd); +} + +static void +IME_Enable(SDL_VideoData *videodata, HWND hwnd) +{ + if (!videodata->ime_initialized || !videodata->ime_hwnd_current) + return; + + if (!videodata->ime_available) { + IME_Disable(videodata, hwnd); + return; + } + if (videodata->ime_hwnd_current == videodata->ime_hwnd_main) + ImmAssociateContext(videodata->ime_hwnd_current, videodata->ime_himc); + + videodata->ime_enabled = SDL_TRUE; + IME_UpdateInputLocale(videodata); + UILess_EnableUIUpdates(videodata); +} + +static void +IME_Disable(SDL_VideoData *videodata, HWND hwnd) +{ + if (!videodata->ime_initialized || !videodata->ime_hwnd_current) + return; + + IME_ClearComposition(videodata); + if (videodata->ime_hwnd_current == videodata->ime_hwnd_main) + ImmAssociateContext(videodata->ime_hwnd_current, NULL); + + videodata->ime_enabled = SDL_FALSE; + UILess_DisableUIUpdates(videodata); +} + +static void +IME_Quit(SDL_VideoData *videodata) +{ + if (!videodata->ime_initialized) + return; + + UILess_ReleaseSinks(videodata); + if (videodata->ime_hwnd_main) + ImmAssociateContext(videodata->ime_hwnd_main, videodata->ime_himc); + + videodata->ime_hwnd_main = 0; + videodata->ime_himc = 0; + if (videodata->ime_himm32) { + FreeLibrary(videodata->ime_himm32); + videodata->ime_himm32 = 0; + } + if (videodata->ime_threadmgr) { + videodata->ime_threadmgr->lpVtbl->Release(videodata->ime_threadmgr); + videodata->ime_threadmgr = 0; + } + if (videodata->ime_com_initialized) { + CoUninitialize(); + videodata->ime_com_initialized = SDL_FALSE; + } + videodata->ime_initialized = SDL_FALSE; +} + +static void +IME_GetReadingString(SDL_VideoData *videodata, HWND hwnd) +{ + DWORD id = 0; + HIMC himc = 0; + WCHAR buffer[16]; + WCHAR *s = buffer; + DWORD len = 0; + DWORD err = 0; + BOOL vertical = FALSE; + UINT maxuilen = 0; + static OSVERSIONINFOA osversion = {0}; + if (videodata->ime_uiless) + return; + + videodata->ime_readingstring[0] = 0; + if (!osversion.dwOSVersionInfoSize) { + osversion.dwOSVersionInfoSize = sizeof(osversion); + GetVersionExA(&osversion); + } + id = IME_GetId(videodata, 0); + if (!id) + return; + + himc = ImmGetContext(hwnd); + if (!himc) + return; + + if (videodata->GetReadingString) { + len = videodata->GetReadingString(himc, 0, 0, &err, &vertical, &maxuilen); + if (len) { + if (len > SDL_arraysize(buffer)) + len = SDL_arraysize(buffer); + + len = videodata->GetReadingString(himc, len, s, &err, &vertical, &maxuilen); + } + SDL_wcslcpy(videodata->ime_readingstring, s, len); + } + else { + LPINPUTCONTEXT2 lpimc = videodata->ImmLockIMC(himc); + LPBYTE p = 0; + s = 0; + switch (id) + { + case IMEID_CHT_VER42: + case IMEID_CHT_VER43: + case IMEID_CHT_VER44: + p = *(LPBYTE *)((LPBYTE)videodata->ImmLockIMCC(lpimc->hPrivate) + 24); + if (!p) + break; + + len = *(DWORD *)(p + 7*4 + 32*4); + s = (WCHAR *)(p + 56); + break; + case IMEID_CHT_VER51: + case IMEID_CHT_VER52: + case IMEID_CHS_VER53: + p = *(LPBYTE *)((LPBYTE)videodata->ImmLockIMCC(lpimc->hPrivate) + 4); + if (!p) + break; + + p = *(LPBYTE *)((LPBYTE)p + 1*4 + 5*4); + if (!p) + break; + + len = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16*2); + s = (WCHAR *)(p + 1*4 + (16*2+2*4) + 5*4); + break; + case IMEID_CHS_VER41: + { + int offset = (IME_GetId(videodata, 1) >= 0x00000002) ? 8 : 7; + p = *(LPBYTE *)((LPBYTE)videodata->ImmLockIMCC(lpimc->hPrivate) + offset * 4); + if (!p) + break; + + len = *(DWORD *)(p + 7*4 + 16*2*4); + s = (WCHAR *)(p + 6*4 + 16*2*1); + } + break; + case IMEID_CHS_VER42: + if (osversion.dwPlatformId != VER_PLATFORM_WIN32_NT) + break; + + p = *(LPBYTE *)((LPBYTE)videodata->ImmLockIMCC(lpimc->hPrivate) + 1*4 + 1*4 + 6*4); + if (!p) + break; + + len = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16*2); + s = (WCHAR *)(p + 1*4 + (16*2+2*4) + 5*4); + break; + } + if (s) + SDL_wcslcpy(videodata->ime_readingstring, s, len + 1); + + videodata->ImmUnlockIMCC(lpimc->hPrivate); + videodata->ImmUnlockIMC(himc); + } + ImmReleaseContext(hwnd, himc); + IME_SendEditingEvent(videodata); +} + +static void +IME_InputLangChanged(SDL_VideoData *videodata) +{ + UINT lang = PRIMLANG(); + HWND hwndime = 0; + IME_UpdateInputLocale(videodata); + IME_SetupAPI(videodata); + if (lang != PRIMLANG()) { + IME_ClearComposition(videodata); + } + hwndime = ImmGetDefaultIMEWnd(videodata->ime_hwnd_current); + if (hwndime) { + SendMessageA(hwndime, WM_IME_CONTROL, IMC_OPENSTATUSWINDOW, 0); + SendMessageA(hwndime, WM_IME_CONTROL, IMC_CLOSESTATUSWINDOW, 0); + } +} + +static DWORD +IME_GetId(SDL_VideoData *videodata, UINT uIndex) +{ + static HKL hklprev = 0; + static DWORD dwRet[2] = {0}; + DWORD dwVerSize = 0; + DWORD dwVerHandle = 0; + LPVOID lpVerBuffer = 0; + LPVOID lpVerData = 0; + UINT cbVerData = 0; + char szTemp[256]; + HKL hkl = 0; + DWORD dwLang = 0; + if (uIndex >= sizeof(dwRet) / sizeof(dwRet[0])) + return 0; + + hkl = videodata->ime_hkl; + if (hklprev == hkl) + return dwRet[uIndex]; + + hklprev = hkl; + dwLang = ((DWORD)hkl & 0xffff); + if (videodata->ime_uiless && LANG() == LANG_CHT) { + dwRet[0] = IMEID_CHT_VER_VISTA; + dwRet[1] = 0; + return dwRet[0]; + } + if (hkl != CHT_HKL_NEW_PHONETIC + && hkl != CHT_HKL_NEW_CHANG_JIE + && hkl != CHT_HKL_NEW_QUICK + && hkl != CHT_HKL_HK_CANTONESE + && hkl != CHS_HKL) { + dwRet[0] = dwRet[1] = 0; + return dwRet[uIndex]; + } + if (ImmGetIMEFileNameA(hkl, szTemp, sizeof(szTemp) - 1) <= 0) { + dwRet[0] = dwRet[1] = 0; + return dwRet[uIndex]; + } + if (!videodata->GetReadingString) { + #define LCID_INVARIANT MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) + if (CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHT_IMEFILENAME1, -1) != 2 + && CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHT_IMEFILENAME2, -1) != 2 + && CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHT_IMEFILENAME3, -1) != 2 + && CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHS_IMEFILENAME1, -1) != 2 + && CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHS_IMEFILENAME2, -1) != 2) { + dwRet[0] = dwRet[1] = 0; + return dwRet[uIndex]; + } + #undef LCID_INVARIANT + dwVerSize = GetFileVersionInfoSizeA(szTemp, &dwVerHandle); + if (dwVerSize) { + lpVerBuffer = SDL_malloc(dwVerSize); + if (lpVerBuffer) { + if (GetFileVersionInfoA(szTemp, dwVerHandle, dwVerSize, lpVerBuffer)) { + if (VerQueryValueA(lpVerBuffer, "\\", &lpVerData, &cbVerData)) { + #define pVerFixedInfo ((VS_FIXEDFILEINFO FAR*)lpVerData) + DWORD dwVer = pVerFixedInfo->dwFileVersionMS; + dwVer = (dwVer & 0x00ff0000) << 8 | (dwVer & 0x000000ff) << 16; + if (videodata->GetReadingString || + dwLang == LANG_CHT && ( + dwVer == MAKEIMEVERSION(4, 2) || + dwVer == MAKEIMEVERSION(4, 3) || + dwVer == MAKEIMEVERSION(4, 4) || + dwVer == MAKEIMEVERSION(5, 0) || + dwVer == MAKEIMEVERSION(5, 1) || + dwVer == MAKEIMEVERSION(5, 2) || + dwVer == MAKEIMEVERSION(6, 0)) + || + dwLang == LANG_CHS && ( + dwVer == MAKEIMEVERSION(4, 1) || + dwVer == MAKEIMEVERSION(4, 2) || + dwVer == MAKEIMEVERSION(5, 3))) { + dwRet[0] = dwVer | dwLang; + dwRet[1] = pVerFixedInfo->dwFileVersionLS; + SDL_free(lpVerBuffer); + return dwRet[0]; + } + #undef pVerFixedInfo + } + } + } + SDL_free(lpVerBuffer); + } + } + dwRet[0] = dwRet[1] = 0; + return dwRet[uIndex]; +} + +static void +IME_SetupAPI(SDL_VideoData *videodata) +{ + char ime_file[MAX_PATH + 1]; + HMODULE hime = 0; + HKL hkl = 0; + videodata->GetReadingString = 0; + videodata->ShowReadingWindow = 0; + if (videodata->ime_uiless) + return; + + hkl = videodata->ime_hkl; + if (ImmGetIMEFileNameA(hkl, ime_file, sizeof(ime_file) - 1) <= 0) + return; + + hime = LoadLibraryA(ime_file); + if (!hime) + return; + + videodata->GetReadingString = (UINT (WINAPI *)(HIMC, UINT, LPWSTR, PINT, BOOL*, PUINT)) + GetProcAddress(hime, "GetReadingString"); + videodata->ShowReadingWindow = (BOOL (WINAPI *)(HIMC, BOOL)) + GetProcAddress(hime, "ShowReadingWindow"); + + if (videodata->ShowReadingWindow) { + HIMC himc = ImmGetContext(videodata->ime_hwnd_current); + if (himc) { + videodata->ShowReadingWindow(himc, FALSE); + ImmReleaseContext(videodata->ime_hwnd_current, himc); + } + } +} + +static void +IME_SetWindow(SDL_VideoData* videodata, HWND hwnd) +{ + videodata->ime_hwnd_current = hwnd; + if (videodata->ime_threadmgr) { + struct ITfDocumentMgr *document_mgr = 0; + if (SUCCEEDED(videodata->ime_threadmgr->lpVtbl->AssociateFocus(videodata->ime_threadmgr, hwnd, NULL, &document_mgr))) { + if (document_mgr) + document_mgr->lpVtbl->Release(document_mgr); + } + } +} + +static void +IME_UpdateInputLocale(SDL_VideoData *videodata) +{ + static HKL hklprev = 0; + videodata->ime_hkl = GetKeyboardLayout(0); + if (hklprev == videodata->ime_hkl) + return; + + hklprev = videodata->ime_hkl; +} + +static void +IME_ClearComposition(SDL_VideoData *videodata) +{ + HIMC himc = 0; + if (!videodata->ime_initialized) + return; + + himc = ImmGetContext(videodata->ime_hwnd_current); + if (!himc) + return; + + ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_CANCEL, 0); + if (videodata->ime_uiless) + ImmSetCompositionString(himc, SCS_SETSTR, TEXT(""), sizeof(TCHAR), TEXT(""), sizeof(TCHAR)); + + ImmNotifyIME(himc, NI_CLOSECANDIDATE, 0, 0); + ImmReleaseContext(videodata->ime_hwnd_current, himc); + SDL_SendEditingText("", 0, 0); +} + +static void +IME_ClearEditing(SDL_VideoData *videodata) +{ + +} + +static void +IME_GetCompositionString(SDL_VideoData *videodata, HIMC himc, DWORD string) +{ + LONG length = ImmGetCompositionStringW(himc, string, videodata->ime_composition, sizeof(videodata->ime_composition)); + if (length < 0) + length = 0; + + length /= sizeof(videodata->ime_composition[0]); + videodata->ime_cursor = LOWORD(ImmGetCompositionStringW(himc, GCS_CURSORPOS, 0, 0)); + if (videodata->ime_composition[videodata->ime_cursor] == 0x3000) { + int i; + for (i = videodata->ime_cursor + 1; i < length; ++i) + videodata->ime_composition[i - 1] = videodata->ime_composition[i]; + + --length; + } + videodata->ime_composition[length] = 0; +} + +static void +IME_SendInputEvent(SDL_VideoData *videodata) +{ + char *s = 0; + s = WIN_StringToUTF8(videodata->ime_composition); + SDL_SendKeyboardText(s); + SDL_free(s); + + videodata->ime_composition[0] = 0; + videodata->ime_readingstring[0] = 0; + videodata->ime_cursor = 0; +} + +static void +IME_SendEditingEvent(SDL_VideoData *videodata) +{ + char *s = 0; + WCHAR buffer[SDL_TEXTEDITINGEVENT_TEXT_SIZE]; + buffer[0] = 0; + if (videodata->ime_readingstring[0]) { + size_t len = SDL_min(SDL_wcslen(videodata->ime_composition), (size_t)videodata->ime_cursor); + SDL_wcslcpy(buffer, videodata->ime_composition, len + 1); + SDL_wcslcat(buffer, videodata->ime_readingstring, sizeof(buffer)); + SDL_wcslcat(buffer, &videodata->ime_composition[len], sizeof(buffer) - len); + } + else { + SDL_wcslcpy(buffer, videodata->ime_composition, sizeof(videodata->ime_composition)); + } + s = WIN_StringToUTF8(buffer); + SDL_SendEditingText(s, videodata->ime_cursor + SDL_wcslen(videodata->ime_readingstring), 0); + SDL_free(s); +} + +SDL_bool +IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoData *videodata) +{ + SDL_bool trap = SDL_FALSE; + HIMC himc = 0; + if (!videodata->ime_initialized || !videodata->ime_available || !videodata->ime_enabled) + return SDL_FALSE; + + switch (msg) + { + case WM_INPUTLANGCHANGE: + //IME_InputLangChanged(videodata); + break; + case WM_IME_SETCONTEXT: + *lParam = 0; + break; + case WM_IME_STARTCOMPOSITION: + trap = SDL_TRUE; + break; + case WM_IME_COMPOSITION: + trap = SDL_TRUE; + himc = ImmGetContext(hwnd); + if (*lParam & GCS_RESULTSTR) { + IME_GetCompositionString(videodata, himc, GCS_RESULTSTR); + IME_SendInputEvent(videodata); + } + if (*lParam & GCS_COMPSTR) { + if (!videodata->ime_uiless) + videodata->ime_readingstring[0] = 0; + + IME_GetCompositionString(videodata, himc, GCS_COMPSTR); + IME_SendEditingEvent(videodata); + } + ImmReleaseContext(hwnd, himc); + break; + case WM_IME_ENDCOMPOSITION: + videodata->ime_composition[0] = 0; + videodata->ime_readingstring[0] = 0; + videodata->ime_cursor = 0; + SDL_SendEditingText("", 0, 0); + break; + case WM_IME_NOTIFY: + switch (wParam) + { + case IMN_SETCONVERSIONMODE: + case IMN_SETOPENSTATUS: + IME_UpdateInputLocale(videodata); + break; + case IMN_OPENCANDIDATE: + case IMN_CHANGECANDIDATE: + trap = SDL_TRUE; + break; + case IMN_CLOSECANDIDATE: + trap = SDL_TRUE; + break; + case IMN_PRIVATE: + { + DWORD dwId = IME_GetId(videodata, 0); + IME_GetReadingString(videodata, hwnd); + switch (dwId) + { + case IMEID_CHT_VER42: + case IMEID_CHT_VER43: + case IMEID_CHT_VER44: + case IMEID_CHS_VER41: + case IMEID_CHS_VER42: + if (*lParam == 1 || *lParam == 2) + trap = SDL_TRUE; + + break; + case IMEID_CHT_VER50: + case IMEID_CHT_VER51: + case IMEID_CHT_VER52: + case IMEID_CHT_VER60: + case IMEID_CHS_VER53: + if (*lParam == 16 + || *lParam == 17 + || *lParam == 26 + || *lParam == 27 + || *lParam == 28) + trap = SDL_TRUE; + break; + } + } + break; + default: + trap = SDL_TRUE; + break; + } + break; + } + return trap; +} + +STDMETHODIMP_(ULONG) TSFSink_AddRef(TSFSink *sink) +{ + return ++sink->refcount; +} + +STDMETHODIMP_(ULONG)TSFSink_Release(TSFSink *sink) +{ + --sink->refcount; + if (sink->refcount == 0) + { + SDL_free(sink); + return 0; + } + return sink->refcount; +} + +STDMETHODIMP UIElementSink_QueryInterface(TSFSink *sink, REFIID riid, PVOID *ppv) +{ + if (!ppv) + return E_INVALIDARG; + + *ppv = 0; + if (SDL_IsEqualIID(riid, &IID_IUnknown)) + *ppv = (IUnknown *)sink; + else if (SDL_IsEqualIID(riid, &IID_ITfUIElementSink)) + *ppv = (ITfUIElementSink *)sink; + + if (*ppv) { + TSFSink_AddRef(sink); + return S_OK; + } + return E_NOINTERFACE; +} + +ITfUIElement *UILess_GetUIElement(SDL_VideoData *videodata, DWORD dwUIElementId) +{ + ITfUIElementMgr *puiem = 0; + ITfUIElement *pelem = 0; + ITfThreadMgrEx *threadmgrex = videodata->ime_threadmgrex; + + if (SUCCEEDED(threadmgrex->lpVtbl->QueryInterface(threadmgrex, &IID_ITfUIElementMgr, (LPVOID *)&puiem))) { + puiem->lpVtbl->GetUIElement(puiem, dwUIElementId, &pelem); + puiem->lpVtbl->Release(puiem); + } + return pelem; +} + +STDMETHODIMP UIElementSink_BeginUIElement(TSFSink *sink, DWORD dwUIElementId, BOOL *pbShow) +{ + ITfUIElement *element = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId); + ITfReadingInformationUIElement *preading = 0; + SDL_VideoData *videodata = (SDL_VideoData *)sink->data; + if (!element) + return E_INVALIDARG; + + *pbShow = FALSE; + if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfReadingInformationUIElement, (LPVOID *)&preading))) { + BSTR bstr; + if (SUCCEEDED(preading->lpVtbl->GetString(preading, &bstr)) && bstr) { + WCHAR *s = (WCHAR *)bstr; + SysFreeString(bstr); + } + preading->lpVtbl->Release(preading); + } + return S_OK; +} + +STDMETHODIMP UIElementSink_UpdateUIElement(TSFSink *sink, DWORD dwUIElementId) +{ + ITfUIElement *element = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId); + ITfReadingInformationUIElement *preading = 0; + SDL_VideoData *videodata = (SDL_VideoData *)sink->data; + if (!element) + return E_INVALIDARG; + + if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfReadingInformationUIElement, (LPVOID *)&preading))) { + BSTR bstr; + if (SUCCEEDED(preading->lpVtbl->GetString(preading, &bstr)) && bstr) { + WCHAR *s = (WCHAR *)bstr; + SDL_wcslcpy(videodata->ime_readingstring, s, sizeof(videodata->ime_readingstring)); + IME_SendEditingEvent(videodata); + SysFreeString(bstr); + } + preading->lpVtbl->Release(preading); + } + return S_OK; +} + +STDMETHODIMP UIElementSink_EndUIElement(TSFSink *sink, DWORD dwUIElementId) +{ + ITfUIElement *element = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId); + ITfReadingInformationUIElement *preading = 0; + SDL_VideoData *videodata = (SDL_VideoData *)sink->data; + if (!element) + return E_INVALIDARG; + + if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfReadingInformationUIElement, (LPVOID *)&preading))) { + videodata->ime_readingstring[0] = 0; + IME_SendEditingEvent(videodata); + preading->lpVtbl->Release(preading); + } + return S_OK; +} + +STDMETHODIMP IPPASink_QueryInterface(TSFSink *sink, REFIID riid, PVOID *ppv) +{ + if (!ppv) + return E_INVALIDARG; + + *ppv = 0; + if (SDL_IsEqualIID(riid, &IID_IUnknown)) + *ppv = (IUnknown *)sink; + else if (SDL_IsEqualIID(riid, &IID_ITfInputProcessorProfileActivationSink)) + *ppv = (ITfInputProcessorProfileActivationSink *)sink; + + if (*ppv) { + TSFSink_AddRef(sink); + return S_OK; + } + return E_NOINTERFACE; +} + +STDMETHODIMP IPPASink_OnActivated(TSFSink *sink, DWORD dwProfileType, LANGID langid, REFCLSID clsid, REFGUID catid, REFGUID guidProfile, HKL hkl, DWORD dwFlags) +{ + if (SDL_IsEqualIID(catid, &GUID_TFCAT_TIP_KEYBOARD) && (dwFlags & TF_IPSINK_FLAG_ACTIVE)) + IME_InputLangChanged((SDL_VideoData *)sink->data); + + return S_OK; +} + +static void *vtUIElementSink[] = { + (void *)(UIElementSink_QueryInterface), + (void *)(TSFSink_AddRef), + (void *)(TSFSink_Release), + (void *)(UIElementSink_BeginUIElement), + (void *)(UIElementSink_UpdateUIElement), + (void *)(UIElementSink_EndUIElement) +}; + +static void *vtIPPASink[] = { + (void *)(IPPASink_QueryInterface), + (void *)(TSFSink_AddRef), + (void *)(TSFSink_Release), + (void *)(IPPASink_OnActivated) +}; + +static void +UILess_EnableUIUpdates(SDL_VideoData *videodata) +{ + ITfSource *source = 0; + if (!videodata->ime_threadmgrex || videodata->ime_uielemsinkcookie != TF_INVALID_COOKIE) + return; + + if (SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, (LPVOID *)&source))) { + source->lpVtbl->AdviseSink(source, &IID_ITfUIElementSink, (IUnknown *)videodata->ime_uielemsink, &videodata->ime_uielemsinkcookie); + source->lpVtbl->Release(source); + } +} + +static void +UILess_DisableUIUpdates(SDL_VideoData *videodata) +{ + ITfSource *source = 0; + if (!videodata->ime_threadmgrex || videodata->ime_uielemsinkcookie == TF_INVALID_COOKIE) + return; + + if (SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, (LPVOID *)&source))) { + source->lpVtbl->UnadviseSink(source, videodata->ime_uielemsinkcookie); + videodata->ime_uielemsinkcookie = TF_INVALID_COOKIE; + source->lpVtbl->Release(source); + } +} + +static SDL_bool +UILess_SetupSinks(SDL_VideoData *videodata) +{ + TfClientId clientid = 0; + SDL_bool result = SDL_FALSE; + ITfSource *source = 0; + if (FAILED(CoCreateInstance(&CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, &IID_ITfThreadMgrEx, &videodata->ime_threadmgrex))) + return SDL_FALSE; + + if (FAILED(videodata->ime_threadmgrex->lpVtbl->ActivateEx(videodata->ime_threadmgrex, &clientid, TF_TMAE_UIELEMENTENABLEDONLY))) + return SDL_FALSE; + + videodata->ime_uielemsink = SDL_malloc(sizeof(TSFSink)); + videodata->ime_ippasink = SDL_malloc(sizeof(TSFSink)); + + videodata->ime_uielemsink->lpVtbl = vtUIElementSink; + videodata->ime_uielemsink->refcount = 1; + videodata->ime_uielemsink->data = videodata; + + videodata->ime_ippasink->lpVtbl = vtIPPASink; + videodata->ime_ippasink->refcount = 1; + videodata->ime_ippasink->data = videodata; + + if (SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, (LPVOID *)&source))) { + if (SUCCEEDED(source->lpVtbl->AdviseSink(source, &IID_ITfUIElementSink, (IUnknown *)videodata->ime_uielemsink, &videodata->ime_uielemsinkcookie))) { + if (SUCCEEDED(source->lpVtbl->AdviseSink(source, &IID_ITfInputProcessorProfileActivationSink, (IUnknown *)videodata->ime_ippasink, &videodata->ime_alpnsinkcookie))) { + result = SDL_TRUE; + } + } + source->lpVtbl->Release(source); + } + return result; +} + +#define SAFE_RELEASE(p) \ +{ \ + if (p) { \ + (p)->lpVtbl->Release((p)); \ + (p) = 0; \ + } \ +} + +static void +UILess_ReleaseSinks(SDL_VideoData *videodata) +{ + ITfSource *source = 0; + if (videodata->ime_threadmgrex && SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, &source))) { + source->lpVtbl->UnadviseSink(source, videodata->ime_uielemsinkcookie); + source->lpVtbl->UnadviseSink(source, videodata->ime_alpnsinkcookie); + SAFE_RELEASE(source); + videodata->ime_threadmgrex->lpVtbl->Deactivate(videodata->ime_threadmgrex); + SAFE_RELEASE(videodata->ime_threadmgrex); + TSFSink_Release(videodata->ime_uielemsink); + videodata->ime_uielemsink = 0; + TSFSink_Release(videodata->ime_ippasink); + videodata->ime_ippasink = 0; + } } /* vi: set ts=4 sw=4 expandtab: */ diff -r 833a225613e2 -r 518d1679d2d0 src/video/win32/SDL_win32keyboard.h --- a/src/video/win32/SDL_win32keyboard.h Sun Aug 22 12:35:34 2010 -0700 +++ b/src/video/win32/SDL_win32keyboard.h Sun Aug 22 12:39:27 2010 -0700 @@ -31,6 +31,12 @@ extern void WIN_UpdateKeymap(void); extern void WIN_QuitKeyboard(_THIS); +extern void WIN_StartTextInput(_THIS); +extern void WIN_StopTextInput(_THIS); +extern void WIN_SetTextInputRect(_THIS, SDL_Rect *rect); + +extern SDL_bool IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, struct SDL_VideoData *videodata); + #endif /* _SDL_win32keyboard_h */ /* vi: set ts=4 sw=4 expandtab: */ diff -r 833a225613e2 -r 518d1679d2d0 src/video/win32/SDL_win32video.c --- a/src/video/win32/SDL_win32video.c Sun Aug 22 12:35:34 2010 -0700 +++ b/src/video/win32/SDL_win32video.c Sun Aug 22 12:39:27 2010 -0700 @@ -191,6 +191,9 @@ device->GL_SwapWindow = WIN_GL_SwapWindow; device->GL_DeleteContext = WIN_GL_DeleteContext; #endif + device->StartTextInput = WIN_StartTextInput; + device->StopTextInput = WIN_StopTextInput; + device->SetTextInputRect = WIN_SetTextInputRect; device->SetClipboardText = WIN_SetClipboardText; device->GetClipboardText = WIN_GetClipboardText; diff -r 833a225613e2 -r 518d1679d2d0 src/video/win32/SDL_win32video.h --- a/src/video/win32/SDL_win32video.h Sun Aug 22 12:35:34 2010 -0700 +++ b/src/video/win32/SDL_win32video.h Sun Aug 22 12:39:27 2010 -0700 @@ -42,6 +42,8 @@ #include +#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 @@ typedef BOOL (*PFNSHFullScreen)(HWND, DWORD); typedef void (*PFCoordTransform)(SDL_Window*, POINT*); +typedef struct +{ + void **lpVtbl; + int refcount; + void *data; +} TSFSink; + +// Definition from Win98DDK version of IMM.H +typedef struct tagINPUTCONTEXT2 { + HWND hWnd; + BOOL fOpen; + POINT ptStatusWndPos; + POINT ptSoftKbdPos; + DWORD fdwConversion; + DWORD fdwSentence; + union { + LOGFONTA A; + LOGFONTW W; + } lfFont; + COMPOSITIONFORM cfCompForm; + CANDIDATEFORM cfCandForm[4]; + HIMCC hCompStr; + HIMCC hCandInfo; + HIMCC hGuideLine; + HIMCC hPrivate; + DWORD dwNumMsgBuf; + HIMCC hMsgBuf; + DWORD fdwInit; + DWORD dwReserve[3]; +} INPUTCONTEXT2, *PINPUTCONTEXT2, NEAR *NPINPUTCONTEXT2, FAR *LPINPUTCONTEXT2; + /* Private display data */ typedef struct SDL_VideoData @@ -97,9 +131,39 @@ PFCoordTransform CoordTransform; #endif + const SDL_scancode *key_layout; DWORD clipboard_count; - const SDL_scancode *key_layout; + SDL_bool ime_com_initialized; + struct ITfThreadMgr *ime_threadmgr; + SDL_bool ime_initialized; + SDL_bool ime_enabled; + SDL_bool ime_available; + HWND ime_hwnd_main; + HWND ime_hwnd_current; + HIMC ime_himc; + + WCHAR ime_composition[SDL_TEXTEDITINGEVENT_TEXT_SIZE]; + WCHAR ime_readingstring[16]; + int ime_cursor; + + HKL ime_hkl; + HMODULE ime_himm32; + UINT (WINAPI *GetReadingString)(HIMC himc, UINT uReadingBufLen, LPWSTR lpwReadingBuf, PINT pnErrorIndex, BOOL *pfIsVertical, PUINT puMaxReadingLen); + BOOL (WINAPI *ShowReadingWindow)(HIMC himc, BOOL bShow); + LPINPUTCONTEXT2 (WINAPI *ImmLockIMC)(HIMC himc); + BOOL (WINAPI *ImmUnlockIMC)(HIMC himc); + LPVOID (WINAPI *ImmLockIMCC)(HIMCC himcc); + BOOL (WINAPI *ImmUnlockIMCC)(HIMCC himcc); + + SDL_bool ime_uiless; + struct ITfThreadMgrEx *ime_threadmgrex; + DWORD ime_uielemsinkcookie; + DWORD ime_alpnsinkcookie; + DWORD ime_openmodesinkcookie; + DWORD ime_convmodesinkcookie; + TSFSink *ime_uielemsink; + TSFSink *ime_ippasink; } SDL_VideoData; #endif /* _SDL_win32video_h */ diff -r 833a225613e2 -r 518d1679d2d0 src/video/win32/SDL_win32window.c --- a/src/video/win32/SDL_win32window.c Sun Aug 22 12:35:34 2010 -0700 +++ b/src/video/win32/SDL_win32window.c Sun Aug 22 12:39:27 2010 -0700 @@ -77,10 +77,12 @@ /* Set up the window proc function */ data->wndproc = (WNDPROC) GetWindowLongPtr(hwnd, GWLP_WNDPROC); - if (data->wndproc == DefWindowProc) { + if (data->wndproc == WIN_WindowProc) { data->wndproc = NULL; } - SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) WIN_WindowProc); + else { + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) WIN_WindowProc); + } /* Fill in the SDL window with the window data */ { diff -r 833a225613e2 -r 518d1679d2d0 test/testime.c --- a/test/testime.c Sun Aug 22 12:35:34 2010 -0700 +++ b/test/testime.c Sun Aug 22 12:39:27 2010 -0700 @@ -25,7 +25,49 @@ SDL_Rect textRect, markedRect; Uint32 lineColor, backColor; SDL_Color textColor = { 0, 0, 0 }; -char text[MAX_TEXT_LENGTH], *markedText; +char text[MAX_TEXT_LENGTH], markedText[SDL_TEXTEDITINGEVENT_TEXT_SIZE]; +int cursor = 0; + +size_t utf8_length(unsigned char c) +{ + c = (unsigned char)(0xff & c); + if (c < 0x80) + return 1; + else if ((c >> 5) ==0x6) + return 2; + else if ((c >> 4) == 0xe) + return 3; + else if ((c >> 3) == 0x1e) + return 4; + else + return 0; +} + +char *utf8_next(char *p) +{ + size_t len = utf8_length(*p); + size_t i = 0; + if (!len) + return 0; + + for (; i < len; ++i) + { + ++p; + if (!*p) + return 0; + } + return p; +} + +char *utf8_advance(char *p, size_t distance) +{ + size_t i = 0; + for (; i < distance && p; ++i) + { + p = utf8_next(p); + } + return p; +} void usage() { @@ -124,7 +166,7 @@ text[0] = 0; markedRect = textRect; - markedText = NULL; + markedText[0] = 0; SDL_StartTextInput(); } @@ -180,9 +222,22 @@ cursorRect.h = h; SDL_FillRect(screen, &markedRect, backColor); - if (markedText) + if (markedText[0]) { #ifdef HAVE_SDL_TTF + if (cursor) + { + char *p = utf8_advance(markedText, cursor); + char c = 0; + if (!p) + p = &markedText[strlen(markedText)]; + + c = *p; + *p = 0; + TTF_SizeUTF8(font, markedText, &w, 0); + cursorRect.x += w; + *p = c; + } RenderText(screen, font, markedText, markedRect.x, markedRect.y, textColor); TTF_SizeUTF8(font, markedText, &w, &h); #endif @@ -192,8 +247,6 @@ underlineRect.h = 2; underlineRect.w = w; - cursorRect.x += w + 1; - SDL_FillRect(screen, &underlineRect, lineColor); } @@ -295,13 +348,13 @@ fprintf(stderr, "Keyboard: text input \"%s\"\n", event.text.text); if (SDL_strlen(text) + SDL_strlen(event.text.text) < sizeof(text)) - SDL_strlcpy(text + SDL_strlen(text), event.text.text, sizeof(text)); + SDL_strlcat(text, event.text.text, sizeof(text)); fprintf(stderr, "text inputed: %s\n", text); // After text inputed, we can clear up markedText because it // is committed - markedText = NULL; + markedText[0] = 0; Redraw(); break; @@ -309,7 +362,8 @@ fprintf(stderr, "text editing \"%s\", selected range (%d, %d)\n", event.edit.text, event.edit.start, event.edit.length); - markedText = event.edit.text; + strcpy(markedText, event.edit.text); + cursor = event.edit.start; Redraw(); break;