Commit 1f8dacab authored by Sam Lantinga's avatar Sam Lantinga

Merged Daniel's Google Summer of Code work from SDL-gsoc2010_IME

parents 66d40ad3 7d245d05

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
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="GLIMM"
ProjectGUID="{F21B830F-20A9-4473-B67A-21D1743C6E19}"
RootNamespace="GLIMM"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)bin"
IntermediateDirectory="obj\$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="include"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="imm32.lib"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)bin"
IntermediateDirectory="obj\$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories="include"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="imm32.lib"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\src\App.cpp"
>
</File>
<File
RelativePath=".\src\IMM.cpp"
>
</File>
<File
RelativePath=".\src\Main.cpp"
>
</File>
<File
RelativePath=".\src\Video_Mode.cpp"
>
</File>
<File
RelativePath=".\src\Window.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\include\App.hpp"
>
</File>
<File
RelativePath=".\include\IMM.hpp"
>
</File>
<File
RelativePath=".\include\Video_Mode.hpp"
>
</File>
<File
RelativePath=".\include\Window.hpp"
>
</File>
<File
RelativePath=".\include\Window_Listener.hpp"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
#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
#ifndef IMM_HPP
#define IMM_HPP
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <msctf.h>
class IMM
{
public:
IMM();
~IMM();
void Initialize(HWND Window);
void Finalize();
LRESULT Handle_Message(HWND Window, UINT Message, WPARAM wParam, LPARAM lParam, bool &Ate);
void Enable();
void Disable();
bool Is_Enabled();
void Toggle();
void Focus_Gained();
void Focus_Lost();
private:
void Update_Input_Locale();
void Cancel_Composition();
void Input_Language_Changed();
bool my_COM_Initialized;
ITfThreadMgr *my_Thread_Manager;
HWND my_Window;
HIMC my_Context;
HKL my_HKL;
bool my_Vertical_Candidates;
bool my_Enabled;
};
#endif
#ifndef VIDEO_MODE_HPP
#define VIDEO_MODE_HPP
#include <cstddef>
class Video_Mode
{
public:
Video_Mode();
Video_Mode(unsigned int The_Width, unsigned int The_Height, unsigned int The_Bits_Per_Pixel);
static Video_Mode Get_Desktop_Mode();
static std::size_t Get_Mode_Count();
static Video_Mode Get_Mode(std::size_t Index);
bool Is_Valid() const;
bool operator==(const Video_Mode &Mode) const;
bool operator!=(const Video_Mode &Mode) const;
unsigned int Width;
unsigned int Height;
unsigned int Bits_Per_Pixel;
private:
static void Initialize_Modes();
};
#endif
#ifndef WINDOW_HPP
#define WINDOW_HPP
#include <string>
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include "Video_Mode.hpp"
#include "Window_Listener.hpp"
#include "IMM.hpp"
class Window
{
public:
Window();
~Window();
void Initialize(const std::wstring &Title, const Video_Mode &Mode, bool Fullscreen);
void Finalize();
void Set_Listener(Window_Listener *Listener);
void Show();
void Hide();
void Handle_Events();
void Display();
void Show_Cursor();
void Hide_Cursor();
HWND Get_Handle();
IMM &Get_IMM();
private:
static const wchar_t *Window_Class_Name;
void Register_Class();
void Unregister_Class();
void Create_Window(const std::wstring &Title, const Video_Mode &Mode, bool Fullscreen);
void Destroy_Window();
void Create_Context(const Video_Mode &Mode);
void Destroy_Context();
void Switch_To_Fullscreen(const Video_Mode &Mode);
LRESULT Handle_Message(HWND Handle, UINT Message, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK Window_Procedure(HWND Handle, UINT Message, WPARAM wParam, LPARAM lParam);
HWND my_Handle;
Video_Mode my_Video_Mode;
bool my_Fullscreen;
HDC my_Device_Context;
HGLRC my_GL_Context;
bool my_Class_Registered;
Window_Listener *my_Listener;
IMM my_IMM;
};
#endif
#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
#include "App.hpp"
#include <GL/gl.h>
#include <GL/glu.h>
#pragma comment(lib, "glu32.lib")
GLfloat Rotation = 0.0f;
App::App() : my_Done(false)
{
}
App::~App()
{
Finalize();
}
void App::Initialize()
{
Finalize();
my_Window.Initialize(L"GLIMM", Video_Mode(Width, Height, Bits_Per_Pixel), Fullscreen);
my_Window.Set_Listener(this);
my_Window.Show();
my_Window.Hide_Cursor();
}
void App::Finalize()
{
my_Window.Finalize();
}
void App::Run()
{
Initialize();
while (!my_Done)
{
my_Window.Handle_Events();
Update();
Draw();
my_Window.Display();
}
}
void App::On_Close()
{
my_Done = true;
my_Window.Hide();
}
void App::On_Key_Down(int Key)
{
switch (Key)
{
case VK_ESCAPE:
On_Close();
break;
}
}
void App::On_Key_Up(int Key)
{
}
void App::On_Char(unsigned int Char)
{
printf("Char: U+%04X\n", Char);
}
void App::On_Resized(unsigned int Width, unsigned int Height)
{
glViewport(0, 0, Width, Height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void App::On_Mouse_Button_Down(Mouse_Button Button)
{
switch (Button)
{
case Mouse_Button_Left:
my_Window.Get_IMM().Toggle();
break;
}
}
void App::Update()
{
Rotation += 0.2f;
}
void App::Draw()
{
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glRotatef(Rotation, 0.0f, 0.0f, -1.0f);
glBegin(GL_TRIANGLES);
glColor3f(0.7f, 0.0f, 0.0f);
glVertex3f(0.0f, 0.5f, 0.0f);
glColor3f(0.0f, 0.7f, 0.0f);
glVertex3f(-0.5f, -0.5f, 0.0f);
glColor3f(0.0f, 0.0f, 0.7f);
glVertex3f(0.5f, -0.5f, 0.0f);
glEnd();
}
#include "IMM.hpp"
#include <stdexcept>
IMM::IMM() : my_COM_Initialized(false),
my_Thread_Manager(0),
my_Window(0),
my_Context(0),
my_HKL(0),
my_Vertical_Candidates(false),
my_Enabled(false)
{
}
IMM::~IMM()
{
Finalize();
}
void IMM::Initialize(HWND Window)
{
Finalize();
my_Window = Window;
if (SUCCEEDED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)))
{
my_COM_Initialized = true;
if (SUCCEEDED(CoCreateInstance(CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, IID_ITfThreadMgr, reinterpret_cast<LPVOID *>(&my_Thread_Manager))))
{
ITfDocumentMgr *Document_Manager = 0;
if (SUCCEEDED(my_Thread_Manager->AssociateFocus(Window, NULL, &Document_Manager)))
{
if (Document_Manager)
Document_Manager->Release();
}
else
printf("Warning: ITfThreadMgr->AssociateFocus failed\n");
}
else
printf("Warning: Failed to create ITfThreadMgr instance\n");
}
else
printf("Warning: Failed to initialize COM\n");
ImmDisableTextFrameService((DWORD)-1);
my_Context = ImmGetContext(my_Window);
ImmReleaseContext(my_Window, my_Context);
if (!my_Context)
throw std::runtime_error("No context (No IME installed?)");
Update_Input_Locale();
Cancel_Composition();
Disable();
}
void IMM::Finalize()
{
if (my_Thread_Manager)
{
my_Thread_Manager->Release();
my_Thread_Manager = 0;
}
if (my_COM_Initialized)
{
CoUninitialize();
my_COM_Initialized = false;
}
}
#define GET_LANG(hkl) LOWORD((hkl))
#define GET_PRIMLANG(hkl) ((WORD)PRIMARYLANGID(GET_LANG((hkl))))
#define GET_SUBLANG(hkl) SUBLANGID(GET_LANG((hkl)))
void IMM::Update_Input_Locale()
{
static HKL Previous_HKL = 0;
my_HKL = GetKeyboardLayout(0);
if (Previous_HKL == my_HKL)
return;
Previous_HKL = my_HKL;
my_Vertical_Candidates = false;
switch (GET_PRIMLANG(my_HKL))
{
case LANG_CHINESE:
my_Vertical_Candidates = true;
switch (GET_SUBLANG(my_HKL))
{
case SUBLANG_CHINESE_SIMPLIFIED:
my_Vertical_Candidates = false;
break;
}
break;
case LANG_JAPANESE:
my_Vertical_Candidates = true;
break;
}
}
LRESULT IMM::Handle_Message(HWND Window, UINT Message, WPARAM wParam, LPARAM lParam, bool &Ate)
{
Ate = false;
switch (Message)
{
case WM_INPUTLANGCHANGE:
Input_Language_Changed();
break;
case WM_IME_SETCONTEXT:
lParam = 0;
break;
case WM_IME_STARTCOMPOSITION:
Ate = true;
break;
case WM_IME_COMPOSITION:
{
Ate = true;
HIMC Context = ImmGetContext(Window);
if (!Context)
break;
if (lParam & GCS_RESULTSTR)
{
LONG Length = ImmGetCompositionStringW(Context, GCS_RESULTSTR, 0, 0);
std::wstring Composition(Length / sizeof(wchar_t), 0);
Length = ImmGetCompositionStringW(Context, GCS_RESULTSTR, &Composition[0], Composition.size() * sizeof(Composition[0]));
printf("GCS_RESULTSTR: ");
for (LONG i = 0; i < Length / sizeof(wchar_t); ++i)
printf("U+%04X ", Composition[i]);
printf("\n");
}
if (lParam & GCS_COMPSTR)
{
LONG Length = ImmGetCompositionStringW(Context, GCS_COMPSTR, 0, 0);
std::wstring Composition(Length / sizeof(wchar_t), 0);
Length = ImmGetCompositionStringW(Context, GCS_COMPSTR, &Composition[0], Composition.size() * sizeof(Composition[0]));
printf("GCS_COMPSTR: ");
for (LONG i = 0; i < Length / sizeof(wchar_t); ++i)
printf("U+%04X ", Composition[i]);
printf("\n");
}
ImmReleaseContext(Window, Context);
}
break;
case WM_IME_ENDCOMPOSITION:
break;
case WM_IME_NOTIFY:
switch (wParam)
{
case IMN_SETCONVERSIONMODE:
break;
case IMN_SETOPENSTATUS:
Update_Input_Locale();
break;
case IMN_OPENCANDIDATE:
case IMN_CHANGECANDIDATE:
Ate = true;
break;
case IMN_CLOSECANDIDATE:
Ate = true;
break;
default:
Ate = true;
break;
}
break;
}
return 0;
}
void IMM::Enable()
{
ImmAssociateContext(my_Window, my_Context);
Update_Input_Locale();
my_Enabled = true;
printf("* Enabled\n");
}
void IMM::Disable()
{
ImmAssociateContext(my_Window, 0);
my_Enabled = false;
printf("* Disabled\n");
}
bool IMM::Is_Enabled()
{
return my_Enabled;
}
void IMM::Toggle()
{
if (my_Enabled)
Disable();
else
Enable();
}
void IMM::Focus_Gained()
{
if (my_Enabled)
Enable();
}
void IMM::Focus_Lost()
{
bool Enabled = my_Enabled;
Cancel_Composition();
Disable();
my_Enabled = Enabled;
}
void IMM::Cancel_Composition()
{
HIMC hIMC = ImmGetContext(my_Window);
if (!hIMC)
return;
ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
ImmNotifyIME(hIMC, NI_CLOSECANDIDATE, 0, 0);
ImmReleaseContext(my_Window, hIMC);
}
void IMM::Input_Language_Changed()
{
Update_Input_Locale();
HWND hwndImeDef = ImmGetDefaultIMEWnd(my_Window);
if (hwndImeDef)
{
SendMessageA(hwndImeDef, WM_IME_CONTROL, IMC_OPENSTATUSWINDOW, 0);
SendMessageA(hwndImeDef, WM_IME_CONTROL, IMC_CLOSESTATUSWINDOW, 0);
}
}
#include "App.hpp"
#include <stdexcept>
int main(int argc, char *argv[])
{
int Result = EXIT_SUCCESS;
try
{
App theApp;
theApp.Run();
}
catch (const std::exception& e)
{
printf("Error: %s\n", e.what());
Result = EXIT_FAILURE;
}
catch (...)
{
printf("Unhandled exception\n");
Result = EXIT_FAILURE;
}
system("PAUSE");
return Result;
}
#include "Video_Mode.hpp"
#include <vector>
#include <algorithm>
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
namespace
{
typedef std::vector<Video_Mode> Video_Mode_List;
Video_Mode_List Supported_Modes;
struct Compare_Modes
{
bool operator()(const Video_Mode &Mode_1, const Video_Mode &Mode_2) const
{
if (Mode_1.Bits_Per_Pixel > Mode_2.Bits_Per_Pixel)
return true;
else if (Mode_1.Bits_Per_Pixel < Mode_2.Bits_Per_Pixel)
return false;
else if (Mode_1.Width > Mode_2.Width)
return true;
else if (Mode_1.Width < Mode_2.Width)
return false;
else
return Mode_1.Height > Mode_2.Height;
}
};
}
Video_Mode::Video_Mode() : Width(0),
Height(0),
Bits_Per_Pixel(0)
{
}
Video_Mode::Video_Mode(unsigned int The_Width, unsigned int The_Height, unsigned int The_Bits_Per_Pixel)
: Width(The_Width),
Height(The_Height),
Bits_Per_Pixel(The_Bits_Per_Pixel)
{
}
Video_Mode Video_Mode::Get_Desktop_Mode()
{
DEVMODE Device_Mode = {0};
Device_Mode.dmSize = sizeof(Device_Mode);
EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &Device_Mode);
return Video_Mode(Device_Mode.dmPelsWidth, Device_Mode.dmPelsHeight, Device_Mode.dmBitsPerPel);
}
std::size_t Video_Mode::Get_Mode_Count()
{
Initialize_Modes();
return Supported_Modes.size();
}
Video_Mode Video_Mode::Get_Mode(std::size_t Index)
{
Initialize_Modes();
return Supported_Modes[Index];
}
bool Video_Mode::Is_Valid() const
{
Initialize_Modes();
return Supported_Modes.end() != std::find(Supported_Modes.begin(), Supported_Modes.end(), *this);
}
bool Video_Mode::operator==(const Video_Mode &Mode) const
{
return (Width == Mode.Width
&& Height == Mode.Height
&& Bits_Per_Pixel == Mode.Bits_Per_Pixel);
}
bool Video_Mode::operator!=(const Video_Mode &Mode) const
{
return !(*this == Mode);
}
void Video_Mode::Initialize_Modes()
{
static bool Initialized = false;
if (!Initialized)
{
DEVMODE Device_Mode = {0};
Device_Mode.dmSize = sizeof(Device_Mode);
for (std::size_t i = 0; 0 != EnumDisplaySettings(NULL, i, &Device_Mode); ++i)
{
Video_Mode Mode(Device_Mode.dmPelsWidth, Device_Mode.dmPelsHeight, Device_Mode.dmBitsPerPel);
if (Supported_Modes.end() == std::find(Supported_Modes.begin(), Supported_Modes.end(), Mode))
Supported_Modes.push_back(Mode);
}
std::sort(Supported_Modes.begin(), Supported_Modes.end(), Compare_Modes());
}
}
#include "Window.hpp"
#include <gl/GL.h>
#pragma comment(lib, "opengl32.lib")
const wchar_t *Window::Window_Class_Name = L"GLTSF";
Window::Window() : my_Handle(0),
my_Device_Context(0),
my_GL_Context(0),
my_Class_Registered(false),
my_Listener(0)
{
}
Window::~Window()
{
Finalize();
Show_Cursor();
}
void Window::Initialize(const std::wstring &Title, const Video_Mode &Mode, bool Fullscreen)
{
Finalize();
my_Video_Mode = Mode;
if (!my_Video_Mode.Is_Valid())
throw std::runtime_error("Invalid video mode");
my_Fullscreen = Fullscreen;
Register_Class();
Create_Window(Title, Mode, Fullscreen);
Show();
my_IMM.Initialize(my_Handle);
}
void Window::Finalize()
{
my_IMM.Finalize();
Destroy_Window();
Unregister_Class();
}
void Window::Set_Listener(Window_Listener *Listener)
{
my_Listener = Listener;
}
void Window::Show()
{
if (my_Handle)
ShowWindow(my_Handle, SW_SHOW);
}
void Window::Hide()
{
if (my_Handle)
ShowWindow(my_Handle, SW_HIDE);
}
void Window::Handle_Events()
{
MSG Message = {0};
while (PeekMessageW(&Message, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&Message);
DispatchMessageW(&Message);
}
}
void Window::Display()
{
if (my_Device_Context && my_GL_Context)
SwapBuffers(my_Device_Context);
}
void Window::Show_Cursor()
{
ShowCursor(TRUE);
}
void Window::Hide_Cursor()
{
ShowCursor(FALSE);
}
HWND Window::Get_Handle()
{
return my_Handle;
}
IMM & Window::Get_IMM()
{
return my_IMM;
}
void Window::Register_Class()
{
WNDCLASSEXW Window_Class = {0};
Window_Class.cbSize = sizeof(Window_Class);
Window_Class.style = 0;
Window_Class.lpfnWndProc = &Window::Window_Procedure;
Window_Class.cbClsExtra = 0;
Window_Class.cbWndExtra = 0;
Window_Class.hInstance = GetModuleHandle(NULL);
Window_Class.hIcon = NULL;
Window_Class.hCursor = NULL;
Window_Class.hbrBackground = NULL;
Window_Class.lpszMenuName = NULL;
Window_Class.lpszClassName = Window_Class_Name;
Window_Class.hIconSm = NULL;
if (0 == RegisterClassExW(&Window_Class))
throw std::runtime_error("Failed to register window class");
my_Class_Registered = true;
}
void Window::Unregister_Class()
{
if (my_Class_Registered)
{
if (0 == UnregisterClassW(Window_Class_Name, GetModuleHandle(NULL)))
printf("Warning: Failed to unregister window class\n");
my_Class_Registered = false;
}
}
void Window::Create_Window(const std::wstring &Title, const Video_Mode &Mode, bool Fullscreen)
{
HDC Screen_DC = GetDC(NULL);
int Left = (GetDeviceCaps(Screen_DC, HORZRES) - my_Video_Mode.Width) / 2;
int Top = (GetDeviceCaps(Screen_DC, VERTRES) - my_Video_Mode.Height) / 2;
int Width = my_Video_Mode.Width;
int Height = my_Video_Mode.Height;
ReleaseDC(NULL, Screen_DC);
DWORD Style = WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;
if (!my_Fullscreen)
{
RECT Rect = {0, 0, Width, Height};
AdjustWindowRect(&Rect, Style, false);
Width = Rect.right - Rect.left;
Height = Rect.bottom - Rect.top;
}
my_Handle = CreateWindowW(Window_Class_Name, Title.c_str(), Style, Left, Top, Width, Height, NULL, NULL, GetModuleHandle(NULL), this);
if (!my_Handle)
throw std::runtime_error("Failed to create window");
if (Fullscreen)
Switch_To_Fullscreen(Mode);
Create_Context(Mode);
RECT Rect = {0};
GetClientRect(my_Handle, &Rect);
//TODO: ...
}
void Window::Destroy_Window()
{
Destroy_Context();
if (my_Handle)
{
DestroyWindow(my_Handle);
my_Handle = 0;
if (my_Fullscreen)
ChangeDisplaySettings(NULL, 0);
}
}
void Window::Create_Context(const Video_Mode &Mode)
{
my_Device_Context = GetDC(my_Handle);
if (!my_Device_Context)
throw std::runtime_error("Failed to get device context");
PIXELFORMATDESCRIPTOR Pixel_Descriptor = {0};
Pixel_Descriptor.nSize = sizeof(Pixel_Descriptor);
Pixel_Descriptor.nVersion = 1;
Pixel_Descriptor.iLayerType = PFD_MAIN_PLANE;
Pixel_Descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
Pixel_Descriptor.iPixelType = PFD_TYPE_RGBA;
Pixel_Descriptor.cColorBits = static_cast<BYTE>(Mode.Bits_Per_Pixel);
Pixel_Descriptor.cDepthBits = 24;
Pixel_Descriptor.cStencilBits = 8;
Pixel_Descriptor.cAlphaBits = Mode.Bits_Per_Pixel == 32 ? 8 : 0;
int Best_Format = ChoosePixelFormat(my_Device_Context, &Pixel_Descriptor);
if (0 == Best_Format)
throw std::runtime_error("Failed to find suitable pixel format");
PIXELFORMATDESCRIPTOR Actual_Format = {0};
Actual_Format.nSize = sizeof(Actual_Format);
Actual_Format.nVersion = 1;
DescribePixelFormat(my_Device_Context, Best_Format, sizeof(Actual_Format), &Actual_Format);
if (!SetPixelFormat(my_Device_Context, Best_Format, &Actual_Format))
throw std::runtime_error("Failed to set device pixel format");
my_GL_Context = wglCreateContext(my_Device_Context);
if (!my_GL_Context)
throw std::runtime_error("Failed to create OpenGL context");
wglMakeCurrent(my_Device_Context, my_GL_Context);
}
void Window::Destroy_Context()
{
if (my_GL_Context)
{
wglDeleteContext(my_GL_Context);
my_GL_Context = 0;
}
if (my_Device_Context)
{
ReleaseDC(my_Handle, my_Device_Context);
my_Device_Context = 0;
}
}
void Window::Switch_To_Fullscreen(const Video_Mode &Mode)
{
DEVMODE Device_Mode = {0};
Device_Mode.dmSize = sizeof(Device_Mode);
Device_Mode.dmPelsWidth = Mode.Width;
Device_Mode.dmPelsHeight = Mode.Height;
Device_Mode.dmBitsPerPel = Mode.Bits_Per_Pixel;
Device_Mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
if (DISP_CHANGE_SUCCESSFUL != ChangeDisplaySettings(&Device_Mode, CDS_FULLSCREEN))
throw std::runtime_error("Failed to change to fullscreen mode");
SetWindowLong(my_Handle, GWL_STYLE, WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
SetWindowLong(my_Handle, GWL_EXSTYLE, WS_EX_APPWINDOW);
SetWindowPos(my_Handle, HWND_TOP, 0, 0, Mode.Width, Mode.Height, SWP_FRAMECHANGED);
}
LRESULT CALLBACK Window::Window_Procedure(HWND Handle, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch (Message)
{
case WM_CREATE:
{
LONG This = reinterpret_cast<LONG>(reinterpret_cast<CREATESTRUCT *>(lParam)->lpCreateParams);
SetWindowLongPtr(Handle, GWLP_USERDATA, This);
return 0;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
break;
default:
{
Window* Win = reinterpret_cast<Window *>(GetWindowLongPtr(Handle, GWLP_USERDATA));
if (Win)
return Win->Handle_Message(Handle, Message, wParam, lParam);
}
break;
}
return DefWindowProcW(Handle, Message, wParam, lParam);
}
#define Call_Listener(x)\
if (my_Listener) my_Listener->x
LRESULT Window::Handle_Message(HWND Handle, UINT Message, WPARAM wParam, LPARAM lParam)
{
bool IMM_Message = false;
LRESULT Result = my_IMM.Handle_Message(Handle, Message, wParam, lParam, IMM_Message);
if (IMM_Message)
return Result;
switch (Message)
{
case WM_SIZE:
Call_Listener(On_Resized(LOWORD(lParam), HIWORD(lParam)));
break;
case WM_CLOSE:
Call_Listener(On_Close());
break;
case WM_KEYDOWN:
Call_Listener(On_Key_Down(wParam));
break;
case WM_KEYUP:
Call_Listener(On_Key_Up(wParam));
break;
case WM_CHAR:
Call_Listener(On_Char(wParam));
break;
case WM_SETFOCUS:
my_IMM.Focus_Gained();
break;
case WM_KILLFOCUS:
my_IMM.Focus_Lost();
break;
case WM_LBUTTONDOWN:
Call_Listener(On_Mouse_Button_Down(Mouse_Button_Left));
break;
case WM_LBUTTONUP:
Call_Listener(On_Mouse_Button_Up(Mouse_Button_Left));
break;
case WM_RBUTTONDOWN:
Call_Listener(On_Mouse_Button_Down(Mouse_Button_Right));
break;
case WM_RBUTTONUP:
Call_Listener(On_Mouse_Button_Up(Mouse_Button_Right));
break;
default:
return DefWindowProcW(Handle, Message, wParam, lParam);
break;
}
return 0;
}

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
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="GLTSF"
ProjectGUID="{FC8A9A48-6667-4BDE-8E9B-5859408AEE83}"
RootNamespace="GLTSF"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)bin"
IntermediateDirectory="obj\$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="include"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)bin"
IntermediateDirectory="obj\$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories="include"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\src\App.cpp"
>
</File>
<File
RelativePath=".\src\Main.cpp"
>
</File>
<File
RelativePath=".\src\TSF.cpp"
>
</File>
<File
RelativePath=".\src\Video_Mode.cpp"
>
</File>
<File
RelativePath=".\src\Window.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\include\App.hpp"
>
</File>
<File
RelativePath=".\include\TSF.hpp"
>
</File>
<File
RelativePath=".\include\Video_Mode.hpp"
>
</File>
<File
RelativePath=".\include\Window.hpp"
>
</File>
<File
RelativePath=".\include\Window_Listener.hpp"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{790D58BA-E5F6-4286-A9C6-0DC28779789D}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>GLTSF</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)bin\</OutDir>
<IntDir>obj\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)bin\</OutDir>
<IntDir>obj\$(Configuration)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="include\App.hpp" />
<ClInclude Include="include\TSF.hpp" />
<ClInclude Include="include\Video_Mode.hpp" />
<ClInclude Include="include\Window.hpp" />
<ClInclude Include="include\Window_Listener.hpp" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\App.cpp" />
<ClCompile Include="src\Main.cpp" />
<ClCompile Include="src\TSF.cpp" />
<ClCompile Include="src\Video_Mode.cpp" />
<ClCompile Include="src\Window.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\App.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Video_Mode.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Window.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Window_Listener.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\TSF.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\App.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Video_Mode.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Window.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\TSF.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
\ No newline at end of file

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
#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
#ifndef TSF_HPP
#define TSF_HPP
#include <msctf.h>
#include <atlbase.h>
class TSF
{
public:
static void Initialize();
static void Finalize();
private:
class TSF_Text_Store : public ITextStoreACP, public ITfContextOwnerCompositionSink
{
public:
//IUnknown
STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
//ITextStoreACP
STDMETHODIMP AdviseSink(REFIID riid, IUnknown *punk, DWORD dwMask);
STDMETHODIMP UnadviseSink(IUnknown *punk);
STDMETHODIMP RequestLock(DWORD dwLockFlags, HRESULT *phrSession);
STDMETHODIMP GetStatus(TS_STATUS *pdcs);
STDMETHODIMP QueryInsert(LONG acpTestStart, LONG acpTestEnd, ULONG cch, LONG *pacpResultStart, LONG *pacpResultEnd);
STDMETHODIMP GetSelection(ULONG ulIndex, ULONG ulCount, TS_SELECTION_ACP *pSelection, ULONG *pcFetched);
STDMETHODIMP SetSelection(ULONG ulCount, const TS_SELECTION_ACP *pSelection);
STDMETHODIMP GetText(LONG acpStart, LONG acpEnd, WCHAR *pchPlain, ULONG cchPlainReq, ULONG *pcchPlainRet, TS_RUNINFO *prgRunInfo, ULONG cRunInfoReq, ULONG *pcRunInfoRet, LONG *pacpNext);
STDMETHODIMP SetText(DWORD dwFlags, LONG acpStart, LONG acpEnd, const WCHAR *pchText, ULONG cch, TS_TEXTCHANGE *pChange);
STDMETHODIMP GetFormattedText(LONG acpStart, LONG acpEnd, IDataObject **ppDataObject);
STDMETHODIMP GetEmbedded(LONG acpPos, REFGUID rguidService, REFIID riid, IUnknown **ppunk);
STDMETHODIMP QueryInsertEmbedded(const GUID *pguidService, const FORMATETC *pFormatEtc, BOOL *pfInsertable);
STDMETHODIMP InsertEmbedded(DWORD dwFlags, LONG acpStart, LONG acpEnd, IDataObject *pDataObject, TS_TEXTCHANGE *pChange);
STDMETHODIMP InsertTextAtSelection(DWORD dwFlags, const WCHAR *pchText, ULONG cch, LONG *pacpStart, LONG *pacpEnd, TS_TEXTCHANGE *pChange);
STDMETHODIMP InsertEmbeddedAtSelection(DWORD dwFlags, IDataObject *pDataObject, LONG *pacpStart, LONG *pacpEnd, TS_TEXTCHANGE *pChange);
STDMETHODIMP RequestSupportedAttrs(DWORD dwFlags, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs);
STDMETHODIMP RequestAttrsAtPosition(LONG acpPos, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs, DWORD dwFlags);
STDMETHODIMP RequestAttrsTransitioningAtPosition(LONG acpPos, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs, DWORD dwFlags);
STDMETHODIMP FindNextAttrTransition(LONG acpStart, LONG acpHalt, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs, DWORD dwFlags, LONG *pacpNext, BOOL *pfFound, LONG *plFoundOffset);
STDMETHODIMP RetrieveRequestedAttrs(ULONG ulCount, TS_ATTRVAL *paAttrVals, ULONG *pcFetched);
STDMETHODIMP GetEndACP(LONG *pacp);
STDMETHODIMP GetActiveView(TsViewCookie *pvcView);
STDMETHODIMP GetACPFromPoint(TsViewCookie vcView, const POINT *ptScreen, DWORD dwFlags, LONG *pacp);
STDMETHODIMP GetTextExt(TsViewCookie vcView, LONG acpStart, LONG acpEnd, RECT *prc, BOOL *pfClipped);
STDMETHODIMP GetScreenExt(TsViewCookie vcView, RECT *prc);
STDMETHODIMP GetWnd(TsViewCookie vcView, HWND *phwnd);
//ITfOwnerCompositionSink
STDMETHODIMP OnStartComposition(ITfCompositionView *pComposition, BOOL *pfOk);
STDMETHODIMP OnUpdateComposition(ITfCompositionView *pComposition, ITfRange *pRangeNew);
STDMETHODIMP OnEndComposition(ITfCompositionView *pComposition);
void Initialize();
void Finalize();
TSF_Text_Store();
~TSF_Text_Store();
private:
ULONG my_Reference_Count;
CComPtr<ITfDocumentMgr> my_Document_Manager;
CComPtr<ITfContext> my_Context;
DWORD my_Edit_Cookie;
CComPtr<ITextStoreACPSink> my_Sink;
DWORD my_Sink_Mask;
DWORD my_Lock;
DWORD my_Lock_Queued;
CComPtr<ITfCompositionView> my_Composition_View;
TS_SELECTION_ACP my_Composition_Selection;
};
TSF();
static bool COM_Initialized;
static CComPtr<ITfThreadMgr> Thread_Manager;
static TfClientId Client_Id;
static TSF_Text_Store *Text_Store;
};
#endif
#ifndef VIDEO_MODE_HPP
#define VIDEO_MODE_HPP
#include <cstddef>
class Video_Mode
{
public:
Video_Mode();
Video_Mode(unsigned int The_Width, unsigned int The_Height, unsigned int The_Bits_Per_Pixel);
static Video_Mode Get_Desktop_Mode();
static std::size_t Get_Mode_Count();
static Video_Mode Get_Mode(std::size_t Index);
bool Is_Valid() const;
bool operator==(const Video_Mode &Mode) const;
bool operator!=(const Video_Mode &Mode) const;
unsigned int Width;
unsigned int Height;
unsigned int Bits_Per_Pixel;
private:
static void Initialize_Modes();
};
#endif
#ifndef WINDOW_HPP
#define WINDOW_HPP
#include <string>
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include "Video_Mode.hpp"
#include "Window_Listener.hpp"
#include "TSF.hpp"
class Window
{
public:
Window();
~Window();
void Initialize(const std::wstring &Title, const Video_Mode &Mode, bool Fullscreen);
void Finalize();
void Set_Listener(Window_Listener *Listener);
void Show();
void Hide();
void Handle_Events();
void Display();
void Show_Cursor();
void Hide_Cursor();
private:
static const wchar_t *Window_Class_Name;
void Register_Class();
void Unregister_Class();
void Create_Window(const std::wstring &Title, const Video_Mode &Mode, bool Fullscreen);
void Destroy_Window();
void Create_Context(const Video_Mode &Mode);
void Destroy_Context();
void Switch_To_Fullscreen(const Video_Mode &Mode);
LRESULT Handle_Message(HWND Handle, UINT Message, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK Window_Procedure(HWND Handle, UINT Message, WPARAM wParam, LPARAM lParam);
HWND my_Handle;
Video_Mode my_Video_Mode;
bool my_Fullscreen;
HDC my_Device_Context;
HGLRC my_GL_Context;
bool my_Class_Registered;
Window_Listener *my_Listener;
};
#endif
#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
#include "App.hpp"
#include "TSF.hpp"
#include <GL/gl.h>
#include <GL/glu.h>
#pragma comment(lib, "glu32.lib")
GLfloat Rotation = 0.0f;
App::App() : my_Done(false)
{
TSF::Initialize();
}
App::~App()
{
Finalize();
TSF::Finalize();
}
void App::Initialize()
{
Finalize();
my_Window.Initialize(L"GLTSF", Video_Mode(Width, Height, Bits_Per_Pixel), Fullscreen);
my_Window.Set_Listener(this);
my_Window.Show();
my_Window.Hide_Cursor();
}
void App::Finalize()
{
my_Window.Finalize();
}
void App::Run()
{
Initialize();
while (!my_Done)
{
my_Window.Handle_Events();
Update();
Draw();
my_Window.Display();
}
}
void App::On_Close()
{
my_Done = true;
my_Window.Hide();
}
void App::On_Key_Down(int Key)
{
switch (Key)
{
case VK_ESCAPE:
On_Close();
break;
}
}
void App::On_Key_Up(int Key)
{
}
void App::On_Char(unsigned int Char)
{
printf("Char: U+%04X\n", Char);
}
void App::On_Resized(unsigned int Width, unsigned int Height)
{
glViewport(0, 0, Width, Height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void App::Update()
{
Rotation += 0.2f;
}
void App::Draw()
{
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glRotatef(Rotation, 0.0f, 0.0f, -1.0f);
glBegin(GL_TRIANGLES);
glColor3f(0.7f, 0.0f, 0.0f);
glVertex3f(0.0f, 0.5f, 0.0f);
glColor3f(0.0f, 0.7f, 0.0f);
glVertex3f(-0.5f, -0.5f, 0.0f);
glColor3f(0.0f, 0.0f, 0.7f);
glVertex3f(0.5f, -0.5f, 0.0f);
glEnd();
}
#include "App.hpp"
#include <stdexcept>
int main(int argc, char *argv[])
{
int Result = EXIT_SUCCESS;
try
{
App theApp;
theApp.Run();
}
catch (const std::exception& e)
{
printf("Error: %s\n", e.what());
Result = EXIT_FAILURE;
}
catch (...)
{
printf("Unhandled exception\n");
Result = EXIT_FAILURE;
}
system("PAUSE");
return Result;
}
#include "TSF.hpp"
#include <stdexcept>
bool TSF::COM_Initialized = false;
CComPtr<ITfThreadMgr> TSF::Thread_Manager;
TfClientId TSF::Client_Id;
TSF::TSF_Text_Store *TSF::Text_Store = NULL;
void TSF::Initialize()
{
if (!COM_Initialized)
{
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (S_OK != hr && S_FALSE != hr)
throw std::runtime_error("Failed to initialize COM");
COM_Initialized = true;
}
if (!Thread_Manager)
{
if (FAILED(CoCreateInstance(CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, IID_ITfThreadMgr, reinterpret_cast<void **>(&Thread_Manager))))
throw std::runtime_error("Failed to create ITfThreadMgr instance");
if (FAILED(Thread_Manager->Activate(&Client_Id)))
throw std::runtime_error("ITfThreadMgr::Activate failed");
Text_Store = new TSF_Text_Store;
Text_Store->Initialize();
}
}
void TSF::Finalize()
{
if (Thread_Manager)
{
Thread_Manager->Deactivate();
Thread_Manager = NULL;
}
if (COM_Initialized)
{
CoUninitialize();
COM_Initialized = false;
}
}
STDMETHODIMP TSF::TSF_Text_Store::QueryInterface(REFIID riid, void **ppvObject)
{
*ppvObject = NULL;
if (IID_IUnknown == riid || IID_ITextStoreACP == riid)
*ppvObject = static_cast<ITextStoreACP *>(this);
else if (IID_ITfContextOwnerCompositionSink == riid)
*ppvObject = static_cast<ITfContextOwnerCompositionSink *>(this);
if (*ppvObject)
{
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) TSF::TSF_Text_Store::AddRef()
{
return ++my_Reference_Count;
}
STDMETHODIMP_(ULONG) TSF::TSF_Text_Store::Release()
{
--my_Reference_Count;
if (0 != my_Reference_Count)
return my_Reference_Count;
delete this;
return 0;
}
#define CHECK_CONDITION(condition, retval, function, line) \
if (!condition) \
{ \
printf("%s:%d: Condition failure: %s\n", function, line, #condition); \
}
#define ENSURE(condition, retval) CHECK_CONDITION(condition, retval, __FUNCTION__, __LINE__)
STDMETHODIMP TSF::TSF_Text_Store::AdviseSink(REFIID riid, IUnknown *punk, DWORD dwMask)
{
ENSURE(punk && IID_ITextStoreACP == riid, E_INVALIDARG);
if (!my_Sink)
{
HRESULT hr = punk->QueryInterface(&my_Sink);
ENSURE(SUCCEEDED(hr) && my_Sink, E_UNEXPECTED);
}
else
{
CComPtr<IUnknown> Unknown_1, Unknown_2;
punk->QueryInterface(&Unknown_1);
my_Sink->QueryInterface(&Unknown_2);
if (Unknown_1 != Unknown_2)
return CONNECT_E_ADVISELIMIT;
}
my_Sink_Mask = dwMask;
return S_OK;
}
STDMETHODIMP TSF::TSF_Text_Store::UnadviseSink(IUnknown *punk)
{
ENSURE(punk, E_INVALIDARG);
ENSURE(my_Sink, CONNECT_E_NOCONNECTION);
CComPtr<IUnknown> Unknown_1, Unknown_2;
punk->QueryInterface(&Unknown_1);
my_Sink->QueryInterface(&Unknown_2);
if (Unknown_1 != Unknown_2)
return CONNECT_E_NOCONNECTION;
my_Sink = NULL;
my_Sink_Mask = 0;
return S_OK;
}
STDMETHODIMP TSF::TSF_Text_Store::RequestLock(DWORD dwLockFlags, HRESULT *phrSession)
{
ENSURE(my_Sink, E_FAIL);
ENSURE(phrSession, E_INVALIDARG);
if (my_Lock)
{
if (TS_LF_READ == (my_Lock & TS_LF_READWRITE)
&& TS_LF_READWRITE == (dwLockFlags & TS_LF_READWRITE)
&& !(dwLockFlags & TS_LF_SYNC))
{
*phrSession = TS_S_ASYNC;
my_Lock_Queued = dwLockFlags & (~TS_LF_SYNC);
}
else
{
*phrSession = TS_E_SYNCHRONOUS;
return E_FAIL;
}
}
else
{
my_Lock = dwLockFlags & (~TS_LF_SYNC);
*phrSession = my_Sink->OnLockGranted(my_Lock);
while (my_Lock_Queued)
{
my_Lock = my_Lock_Queued;
my_Lock_Queued = 0;
my_Sink->OnLockGranted(my_Lock);
}
my_Lock = 0;
}
return S_OK;
}
STDMETHODIMP TSF::TSF_Text_Store::GetStatus(TS_STATUS *pdcs)
{
ENSURE(pdcs, E_INVALIDARG);
pdcs->dwDynamicFlags = 0;
pdcs->dwStaticFlags = TS_SS_NOHIDDENTEXT;
return S_OK;
}
STDMETHODIMP TSF::TSF_Text_Store::QueryInsert(LONG acpTestStart, LONG acpTestEnd, ULONG cch, LONG *pacpResultStart, LONG *pacpResultEnd)
{
ENSURE(0 <= acpTestStart && acpTestStart <= acpTestEnd && pacpResultStart && pacpResultEnd, E_INVALIDARG);
*pacpResultStart = acpTestStart;
*pacpResultEnd = acpTestStart + cch;
return S_OK;
}
STDMETHODIMP TSF::TSF_Text_Store::GetSelection(ULONG ulIndex, ULONG ulCount, TS_SELECTION_ACP *pSelection, ULONG *pcFetched)
{
ENSURE(TS_LF_READ == (my_Lock && TS_LF_READ), TS_E_NOLOCK);
ENSURE(ulCount && pSelection && pcFetched, E_INVALIDARG);
*pcFetched = 0;
ENSURE(TS_DEFAULT_SELECTION == ulIndex || 0 == ulIndex, TS_E_NOSELECTION);
if (my_Composition_View)
{
*pSelection = my_Composition_Selection;
}
else
{
//TODO
}
*pcFetched = 1;
return S_OK;
}
STDMETHODIMP TSF::TSF_Text_Store::SetSelection(ULONG ulCount, const TS_SELECTION_ACP *pSelection)
{
return E_NOTIMPL;
}
STDMETHODIMP TSF::TSF_Text_Store::GetText(LONG acpStart, LONG acpEnd, WCHAR *pchPlain, ULONG cchPlainReq, ULONG *pcchPlainRet, TS_RUNINFO *prgRunInfo, ULONG cRunInfoReq, ULONG *pcRunInfoRet, LONG *pacpNext)
{
ENSURE(TS_LF_READ == (my_Lock & TS_LF_READ), TS_E_NOLOCK);
ENSURE(pcchPlainRet && (pchPlain || prgRunInfo)
&& (!cchPlainReq == !pchPlain)
&& (!cRunInfoReq == !prgRunInfo), E_INVALIDARG);
ENSURE(0 <= acpStart && -1 <= acpEnd
&& (-1 == acpEnd || acpStart <= acpEnd), TS_E_INVALIDPOS);
*pcchPlainRet = 0;
if (pchPlain && cchPlainReq) *pchPlain = 0;
if (pcRunInfoRet) *pcRunInfoRet = 0;
//TODO
return S_OK;
}
STDMETHODIMP TSF::TSF_Text_Store::SetText(DWORD dwFlags, LONG acpStart, LONG acpEnd, const WCHAR *pchText, ULONG cch, TS_TEXTCHANGE *pChange)
{
return E_NOTIMPL;
}
STDMETHODIMP TSF::TSF_Text_Store::GetFormattedText(LONG acpStart, LONG acpEnd, IDataObject **ppDataObject)
{
//not needed
return E_NOTIMPL;
}
STDMETHODIMP TSF::TSF_Text_Store::GetEmbedded(LONG acpPos, REFGUID rguidService, REFIID riid, IUnknown **ppunk)
{
//not needed
return E_NOTIMPL;
}
STDMETHODIMP TSF::TSF_Text_Store::QueryInsertEmbedded(const GUID *pguidService, const FORMATETC *pFormatEtc, BOOL *pfInsertable)
{
if (!pfInsertable)
return E_INVALIDARG;
//Not supported
*pfInsertable = FALSE;
return E_NOTIMPL;
}
STDMETHODIMP TSF::TSF_Text_Store::InsertEmbedded(DWORD dwFlags, LONG acpStart, LONG acpEnd, IDataObject *pDataObject, TS_TEXTCHANGE *pChange)
{
return E_NOTIMPL;
}
STDMETHODIMP TSF::TSF_Text_Store::InsertTextAtSelection(DWORD dwFlags, const WCHAR *pchText, ULONG cch, LONG *pacpStart, LONG *pacpEnd, TS_TEXTCHANGE *pChange)
{
return E_NOTIMPL;
}
STDMETHODIMP TSF::TSF_Text_Store::InsertEmbeddedAtSelection(DWORD dwFlags, IDataObject *pDataObject, LONG *pacpStart, LONG *pacpEnd, TS_TEXTCHANGE *pChange)
{
//not needed
return E_NOTIMPL;
}
STDMETHODIMP TSF::TSF_Text_Store::RequestSupportedAttrs(DWORD dwFlags, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs)
{
//not needed
return E_NOTIMPL;
}
STDMETHODIMP TSF::TSF_Text_Store::RequestAttrsAtPosition(LONG acpPos, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs, DWORD dwFlags)
{
//not needed
return E_NOTIMPL;
}
STDMETHODIMP TSF::TSF_Text_Store::RequestAttrsTransitioningAtPosition(LONG acpPos, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs, DWORD dwFlags)
{
//not needed
return E_NOTIMPL;
}
STDMETHODIMP TSF::TSF_Text_Store::FindNextAttrTransition(LONG acpStart, LONG acpHalt, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs, DWORD dwFlags, LONG *pacpNext, BOOL *pfFound, LONG *plFoundOffset)
{
//not needed
return E_NOTIMPL;
}
STDMETHODIMP TSF::TSF_Text_Store::RetrieveRequestedAttrs(ULONG ulCount, TS_ATTRVAL *paAttrVals, ULONG *pcFetched)
{
//not needed
return E_NOTIMPL;
}
STDMETHODIMP TSF::TSF_Text_Store::GetEndACP(LONG *pacp)
{
return E_NOTIMPL;
}
STDMETHODIMP TSF::TSF_Text_Store::GetActiveView(TsViewCookie *pvcView)
{
return E_NOTIMPL;
}
STDMETHODIMP TSF::TSF_Text_Store::GetACPFromPoint(TsViewCookie vcView, const POINT *ptScreen, DWORD dwFlags, LONG *pacp)
{
return E_NOTIMPL;
}
STDMETHODIMP TSF::TSF_Text_Store::GetTextExt(TsViewCookie vcView, LONG acpStart, LONG acpEnd, RECT *prc, BOOL *pfClipped)
{
return E_NOTIMPL;
}
STDMETHODIMP TSF::TSF_Text_Store::GetScreenExt(TsViewCookie vcView, RECT *prc)
{
return E_NOTIMPL;
}
STDMETHODIMP TSF::TSF_Text_Store::GetWnd(TsViewCookie vcView, HWND *phwnd)
{
return E_NOTIMPL;
}
STDMETHODIMP TSF::TSF_Text_Store::OnStartComposition(ITfCompositionView *pComposition, BOOL *pfOk)
{
return E_NOTIMPL;
}
STDMETHODIMP TSF::TSF_Text_Store::OnUpdateComposition(ITfCompositionView *pComposition, ITfRange *pRangeNew)
{
return E_NOTIMPL;
}
STDMETHODIMP TSF::TSF_Text_Store::OnEndComposition(ITfCompositionView *pComposition)
{
return E_NOTIMPL;
}
TSF::TSF_Text_Store::TSF_Text_Store() : my_Reference_Count(1),
my_Edit_Cookie(0),
my_Lock(0),
my_Lock_Queued(0)
{
}
TSF::TSF_Text_Store::~TSF_Text_Store()
{
}
void TSF::TSF_Text_Store::Initialize()
{
if (FAILED(Thread_Manager->CreateDocumentMgr(&my_Document_Manager)))
throw std::runtime_error("Failed to create document manager");
if (FAILED(my_Document_Manager->CreateContext(Client_Id, 0, static_cast<ITextStoreACP *>(this), &my_Context, &my_Edit_Cookie)))
throw std::runtime_error("Failed to create document context");
if (FAILED(my_Document_Manager->Push(my_Context)))
throw std::runtime_error("Failed to push context");
}
void TSF::TSF_Text_Store::Finalize()
{
}
#include "Video_Mode.hpp"
#include <vector>
#include <algorithm>
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
namespace
{
typedef std::vector<Video_Mode> Video_Mode_List;
Video_Mode_List Supported_Modes;
struct Compare_Modes
{
bool operator()(const Video_Mode &Mode_1, const Video_Mode &Mode_2) const
{
if (Mode_1.Bits_Per_Pixel > Mode_2.Bits_Per_Pixel)
return true;
else if (Mode_1.Bits_Per_Pixel < Mode_2.Bits_Per_Pixel)
return false;
else if (Mode_1.Width > Mode_2.Width)
return true;
else if (Mode_1.Width < Mode_2.Width)
return false;
else
return Mode_1.Height > Mode_2.Height;
}
};
}
Video_Mode::Video_Mode() : Width(0),
Height(0),
Bits_Per_Pixel(0)
{
}
Video_Mode::Video_Mode(unsigned int The_Width, unsigned int The_Height, unsigned int The_Bits_Per_Pixel)
: Width(The_Width),
Height(The_Height),
Bits_Per_Pixel(The_Bits_Per_Pixel)
{
}
Video_Mode Video_Mode::Get_Desktop_Mode()
{
DEVMODE Device_Mode = {0};
Device_Mode.dmSize = sizeof(Device_Mode);
EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &Device_Mode);
return Video_Mode(Device_Mode.dmPelsWidth, Device_Mode.dmPelsHeight, Device_Mode.dmBitsPerPel);
}
std::size_t Video_Mode::Get_Mode_Count()
{
Initialize_Modes();
return Supported_Modes.size();
}
Video_Mode Video_Mode::Get_Mode(std::size_t Index)
{
Initialize_Modes();
return Supported_Modes[Index];
}
bool Video_Mode::Is_Valid() const
{
Initialize_Modes();
return Supported_Modes.end() != std::find(Supported_Modes.begin(), Supported_Modes.end(), *this);
}
bool Video_Mode::operator==(const Video_Mode &Mode) const
{
return (Width == Mode.Width
&& Height == Mode.Height
&& Bits_Per_Pixel == Mode.Bits_Per_Pixel);
}
bool Video_Mode::operator!=(const Video_Mode &Mode) const
{
return !(*this == Mode);
}
void Video_Mode::Initialize_Modes()
{
static bool Initialized = false;
if (!Initialized)
{
DEVMODE Device_Mode = {0};
Device_Mode.dmSize = sizeof(Device_Mode);
for (std::size_t i = 0; 0 != EnumDisplaySettings(NULL, i, &Device_Mode); ++i)
{
Video_Mode Mode(Device_Mode.dmPelsWidth, Device_Mode.dmPelsHeight, Device_Mode.dmBitsPerPel);
if (Supported_Modes.end() == std::find(Supported_Modes.begin(), Supported_Modes.end(), Mode))
Supported_Modes.push_back(Mode);
}
std::sort(Supported_Modes.begin(), Supported_Modes.end(), Compare_Modes());
}
}
#include "Window.hpp"
#include <gl/GL.h>
#pragma comment(lib, "opengl32.lib")
const wchar_t *Window::Window_Class_Name = L"GLTSF";
Window::Window() : my_Handle(0),
my_Device_Context(0),
my_GL_Context(0),
my_Class_Registered(false),
my_Listener(0)
{
}
Window::~Window()
{
Finalize();
Show_Cursor();
}
void Window::Initialize(const std::wstring &Title, const Video_Mode &Mode, bool Fullscreen)
{
Finalize();
my_Video_Mode = Mode;
if (!my_Video_Mode.Is_Valid())
throw std::runtime_error("Invalid video mode");
my_Fullscreen = Fullscreen;
Register_Class();
Create_Window(Title, Mode, Fullscreen);
}
void Window::Finalize()
{
Destroy_Window();
Unregister_Class();
}
void Window::Set_Listener(Window_Listener *Listener)
{
my_Listener = Listener;
}
void Window::Register_Class()
{
WNDCLASSEXW Window_Class = {0};
Window_Class.cbSize = sizeof(Window_Class);
Window_Class.style = 0;
Window_Class.lpfnWndProc = &Window::Window_Procedure;
Window_Class.cbClsExtra = 0;
Window_Class.cbWndExtra = 0;
Window_Class.hInstance = GetModuleHandle(NULL);
Window_Class.hIcon = NULL;
Window_Class.hCursor = NULL;
Window_Class.hbrBackground = NULL;
Window_Class.lpszMenuName = NULL;
Window_Class.lpszClassName = Window_Class_Name;
Window_Class.hIconSm = NULL;
if (0 == RegisterClassExW(&Window_Class))
throw std::runtime_error("Failed to register window class");
my_Class_Registered = true;
}
void Window::Unregister_Class()
{
if (my_Class_Registered)
{
if (0 == UnregisterClassW(Window_Class_Name, GetModuleHandle(NULL)))
printf("Warning: Failed to unregister window class\n");
my_Class_Registered = false;
}
}
void Window::Create_Window(const std::wstring &Title, const Video_Mode &Mode, bool Fullscreen)
{
HDC Screen_DC = GetDC(NULL);
int Left = (GetDeviceCaps(Screen_DC, HORZRES) - my_Video_Mode.Width) / 2;
int Top = (GetDeviceCaps(Screen_DC, VERTRES) - my_Video_Mode.Height) / 2;
int Width = my_Video_Mode.Width;
int Height = my_Video_Mode.Height;
ReleaseDC(NULL, Screen_DC);
DWORD Style = WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;
if (!my_Fullscreen)
{
RECT Rect = {0, 0, Width, Height};
AdjustWindowRect(&Rect, Style, false);
Width = Rect.right - Rect.left;
Height = Rect.bottom - Rect.top;
}
my_Handle = CreateWindowW(Window_Class_Name, Title.c_str(), Style, Left, Top, Width, Height, NULL, NULL, GetModuleHandle(NULL), this);
if (!my_Handle)
throw std::runtime_error("Failed to create window");
if (Fullscreen)
Switch_To_Fullscreen(Mode);
Create_Context(Mode);
RECT Rect = {0};
GetClientRect(my_Handle, &Rect);
//TODO: ...
}
void Window::Destroy_Window()
{
Destroy_Context();
if (my_Handle)
{
DestroyWindow(my_Handle);
my_Handle = 0;
if (my_Fullscreen)
ChangeDisplaySettings(NULL, 0);
}
}
void Window::Create_Context(const Video_Mode &Mode)
{
my_Device_Context = GetDC(my_Handle);
if (!my_Device_Context)
throw std::runtime_error("Failed to get device context");
PIXELFORMATDESCRIPTOR Pixel_Descriptor = {0};
Pixel_Descriptor.nSize = sizeof(Pixel_Descriptor);
Pixel_Descriptor.nVersion = 1;
Pixel_Descriptor.iLayerType = PFD_MAIN_PLANE;
Pixel_Descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
Pixel_Descriptor.iPixelType = PFD_TYPE_RGBA;
Pixel_Descriptor.cColorBits = static_cast<BYTE>(Mode.Bits_Per_Pixel);
Pixel_Descriptor.cDepthBits = 24;
Pixel_Descriptor.cStencilBits = 8;
Pixel_Descriptor.cAlphaBits = Mode.Bits_Per_Pixel == 32 ? 8 : 0;
int Best_Format = ChoosePixelFormat(my_Device_Context, &Pixel_Descriptor);
if (0 == Best_Format)
throw std::runtime_error("Failed to find suitable pixel format");
PIXELFORMATDESCRIPTOR Actual_Format = {0};
Actual_Format.nSize = sizeof(Actual_Format);
Actual_Format.nVersion = 1;
DescribePixelFormat(my_Device_Context, Best_Format, sizeof(Actual_Format), &Actual_Format);
if (!SetPixelFormat(my_Device_Context, Best_Format, &Actual_Format))
throw std::runtime_error("Failed to set device pixel format");
my_GL_Context = wglCreateContext(my_Device_Context);
if (!my_GL_Context)
throw std::runtime_error("Failed to create OpenGL context");
wglMakeCurrent(my_Device_Context, my_GL_Context);
}
void Window::Destroy_Context()
{
if (my_GL_Context)
{
wglDeleteContext(my_GL_Context);
my_GL_Context = 0;
}
if (my_Device_Context)
{
ReleaseDC(my_Handle, my_Device_Context);
my_Device_Context = 0;
}
}
void Window::Switch_To_Fullscreen(const Video_Mode &Mode)
{
DEVMODE Device_Mode = {0};
Device_Mode.dmSize = sizeof(Device_Mode);
Device_Mode.dmPelsWidth = Mode.Width;
Device_Mode.dmPelsHeight = Mode.Height;
Device_Mode.dmBitsPerPel = Mode.Bits_Per_Pixel;
Device_Mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
if (DISP_CHANGE_SUCCESSFUL != ChangeDisplaySettings(&Device_Mode, CDS_FULLSCREEN))
throw std::runtime_error("Failed to change to fullscreen mode");
SetWindowLong(my_Handle, GWL_STYLE, WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
SetWindowLong(my_Handle, GWL_EXSTYLE, WS_EX_APPWINDOW);
SetWindowPos(my_Handle, HWND_TOP, 0, 0, Mode.Width, Mode.Height, SWP_FRAMECHANGED);
}
LRESULT CALLBACK Window::Window_Procedure(HWND Handle, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch (Message)
{
case WM_CREATE:
{
LONG This = reinterpret_cast<LONG>(reinterpret_cast<CREATESTRUCT *>(lParam)->lpCreateParams);
SetWindowLongPtr(Handle, GWLP_USERDATA, This);
return 0;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
break;
default:
{
Window* Win = reinterpret_cast<Window *>(GetWindowLongPtr(Handle, GWLP_USERDATA));
if (Win)
return Win->Handle_Message(Handle, Message, wParam, lParam);
}
break;
}
return DefWindowProcW(Handle, Message, wParam, lParam);
}
#define Call_Listener(x)\
if (my_Listener) my_Listener->x
LRESULT Window::Handle_Message(HWND Handle, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch (Message)
{
case WM_SIZE:
Call_Listener(On_Resized(LOWORD(lParam), HIWORD(lParam)));
break;
case WM_CLOSE:
Call_Listener(On_Close());
break;
case WM_KEYDOWN:
Call_Listener(On_Key_Down(wParam));
break;
case WM_KEYUP:
Call_Listener(On_Key_Up(wParam));
break;
case WM_CHAR:
Call_Listener(On_Char(wParam));
break;
default:
return DefWindowProcW(Handle, Message, wParam, lParam);
break;
}
return 0;
}
void Window::Show()
{
if (my_Handle)
ShowWindow(my_Handle, SW_SHOW);
}
void Window::Hide()
{
if (my_Handle)
ShowWindow(my_Handle, SW_HIDE);
}
void Window::Handle_Events()
{
MSG Message = {0};
while (PeekMessageW(&Message, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&Message);
DispatchMessageW(&Message);
}
}
void Window::Display()
{
if (my_Device_Context && my_GL_Context)
SwapBuffers(my_Device_Context);
}
void Window::Show_Cursor()
{
ShowCursor(TRUE);
}
void Window::Hide_Cursor()
{
ShowCursor(FALSE);
}
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
......@@ -472,6 +472,19 @@ extern DECLSPEC size_t SDLCALL SDL_strlen(const char *string);
extern DECLSPEC size_t SDLCALL SDL_wcslen(const wchar_t * string);
#endif
#ifdef HAVE_WCSLCPY
#define SDL_wcslcpy wcslcpy
#else
extern DECLSPEC size_t SDLCALL SDL_wcslcpy(wchar_t *dst, const wchar_t *src, size_t maxlen);
#endif
#ifdef HAVE_WCSLCAT
#define SDL_wcslcat wcslcat
#else
extern DECLSPEC size_t SDLCALL SDL_wcslcat(wchar_t *dst, const wchar_t *src, size_t maxlen);
#endif
#ifdef HAVE_STRLCPY
#define SDL_strlcpy strlcpy
#else
......@@ -479,6 +492,9 @@ extern DECLSPEC size_t SDLCALL SDL_strlcpy(char *dst, const char *src,
size_t maxlen);
#endif
extern DECLSPEC size_t SDLCALL SDL_utf8strlcpy(char *dst, const char *src,
size_t dst_bytes);
#ifdef HAVE_STRLCAT
#define SDL_strlcat strlcat
#else
......
......@@ -778,7 +778,7 @@ SDL_SendKeyboardText(const char *text)
SDL_Event event;
event.text.type = SDL_TEXTINPUT;
event.text.windowID = keyboard->focus ? keyboard->focus->id : 0;
SDL_strlcpy(event.text.text, text, SDL_arraysize(event.text.text));
SDL_utf8strlcpy(event.text.text, text, SDL_arraysize(event.text.text));
event.text.windowID = keyboard->focus ? keyboard->focus->id : 0;
posted = (SDL_PushEvent(&event) > 0);
}
......@@ -799,7 +799,7 @@ SDL_SendEditingText(const char *text, int start, int length)
event.edit.windowID = keyboard->focus ? keyboard->focus->id : 0;
event.edit.start = start;
event.edit.length = length;
SDL_strlcpy(event.edit.text, text, SDL_arraysize(event.edit.text));
SDL_utf8strlcpy(event.edit.text, text, SDL_arraysize(event.edit.text));
posted = (SDL_PushEvent(&event) > 0);
}
return (posted);
......
......@@ -43,35 +43,35 @@ typedef struct
} NDS_HapticData;
void
NDS_EZF_OpenNorWrite()
void
NDS_EZF_OpenNorWrite()
{
GBA_BUS[0x0FF0000] = 0xD200;
GBA_BUS[0x0000000] = 0x1500;
GBA_BUS[0x0010000] = 0xD200;
GBA_BUS[0x0020000] = 0x1500;
GBA_BUS[0x0E20000] = 0x1500;
GBA_BUS[0x0FE0000] = 0x1500;
} void
NDS_EZF_CloseNorWrite()
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()
{
GBA_BUS[0x0FF0000] = 0xD200;
GBA_BUS[0x0000000] = 0x1500;
GBA_BUS[0x0010000] = 0xD200;
GBA_BUS[0x0020000] = 0x1500;
GBA_BUS[0x0E20000] = 0xD200;
GBA_BUS[0x0FE0000] = 0x1500;
}
GBA_BUS[0x0FF0000] = 0xD200;
GBA_BUS[0x0000000] = 0x1500;
GBA_BUS[0x0010000] = 0xD200;
GBA_BUS[0x0020000] = 0x1500;
GBA_BUS[0x0E20000] = 0xD200;
GBA_BUS[0x0FE0000] = 0x1500;
}
void
NDS_EZF_ChipReset()
{
GBA_BUS[0x0000] = 0x00F0;
GBA_BUS[0x1000] = 0x00F0;
} uint32 NDS_EZF_IsPresent()
GBA_BUS[0x0000] = 0x00F0;
GBA_BUS[0x1000] = 0x00F0;
} uint32 NDS_EZF_IsPresent()
{
vuint16 id1, id2;
vuint16 id1, id2;
NDS_EZF_OpenNorWrite();
......@@ -81,35 +81,35 @@ NDS_EZF_ChipReset()
GBA_BUS[0x1555] = 0x00AA;
GBA_BUS[0x12AA] = 0x0055;
GBA_BUS[0x1555] = 0x0090;
id1 = GBA_BUS[0x0001];
id2 = GBA_BUS[0x1001];
if ((id1 != 0x227E) || (id2 != 0x227E)) {
id1 = GBA_BUS[0x0001];
id2 = GBA_BUS[0x1001];
if ((id1 != 0x227E) || (id2 != 0x227E)) {
NDS_EZF_CloseNorWrite();
return 0;
return 0;
}
id1 = GBA_BUS[0x000E];
id2 = GBA_BUS[0x100E];
id1 = GBA_BUS[0x000E];
id2 = GBA_BUS[0x100E];
NDS_EZF_CloseNorWrite();
if (id1 == 0x2218 && id2 == 0x2218) {
return 1;
if (id1 == 0x2218 && id2 == 0x2218) {
return 1;
}
return 0;
}
void
NDS_EZF_SetShake(u8 pos)
return 0;
}
void
NDS_EZF_SetShake(u8 pos)
{
u16 data = ((pos % 3) | 0x00F0);
GBA_BUS[0x0FF0000] = 0xD200;
GBA_BUS[0x0000000] = 0x1500;
GBA_BUS[0x0010000] = 0xD200;
GBA_BUS[0x0020000] = 0x1500;
GBA_BUS[0x0F10000] = data;
GBA_BUS[0x0FE0000] = 0x1500;
GBA_BUS[0x0FF0000] = 0xD200;
GBA_BUS[0x0000000] = 0x1500;
GBA_BUS[0x0010000] = 0xD200;
GBA_BUS[0x0020000] = 0x1500;
GBA_BUS[0x0F10000] = data;
GBA_BUS[0x0FE0000] = 0x1500;
GBA_BUS[0] = 0x0000; /* write any value for vibration. */
GBA_BUS[0] = 0x0002;
}
}
static int
SDL_SYS_LogicError(void)
......
......@@ -45,7 +45,7 @@ int
SDL_SYS_JoystickInit(void)
{
SDL_numjoysticks = 1;
return (1);
return (1);
}
/* Function to get the device-dependent name of a joystick */
......@@ -73,7 +73,7 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick)
return 0;
}
/* Function to update the state of a joystick - called as a device poll.
* This function shouldn't update the joystick structure directly,
* but instead should call SDL_PrivateJoystick*() to deliver events
......@@ -84,8 +84,8 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
{
u32 keysd, keysu;
int magnitude = 16384;
/*scanKeys(); - this is done in PumpEvents, because touch uses it too */
/*scanKeys(); - this is done in PumpEvents, because touch uses it too */
keysd = keysDown();
keysu = keysUp();
......@@ -101,61 +101,61 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
if ((keysd & KEY_RIGHT)) {
SDL_PrivateJoystickAxis(joystick, 0, magnitude);
}
if ((keysu & (KEY_UP | KEY_DOWN))) {
if ((keysu & (KEY_UP | KEY_DOWN))) {
SDL_PrivateJoystickAxis(joystick, 1, 0);
}
if ((keysu & (KEY_LEFT | KEY_RIGHT))) {
if ((keysu & (KEY_LEFT | KEY_RIGHT))) {
SDL_PrivateJoystickAxis(joystick, 0, 0);
}
if ((keysd & KEY_A)) {
if ((keysd & KEY_A)) {
SDL_PrivateJoystickButton(joystick, 0, SDL_PRESSED);
}
if ((keysd & KEY_B)) {
if ((keysd & KEY_B)) {
SDL_PrivateJoystickButton(joystick, 1, SDL_PRESSED);
}
if ((keysd & KEY_X)) {
if ((keysd & KEY_X)) {
SDL_PrivateJoystickButton(joystick, 2, SDL_PRESSED);
}
if ((keysd & KEY_Y)) {
if ((keysd & KEY_Y)) {
SDL_PrivateJoystickButton(joystick, 3, SDL_PRESSED);
}
if ((keysd & KEY_L)) {
if ((keysd & KEY_L)) {
SDL_PrivateJoystickButton(joystick, 4, SDL_PRESSED);
}
if ((keysd & KEY_R)) {
if ((keysd & KEY_R)) {
SDL_PrivateJoystickButton(joystick, 5, SDL_PRESSED);
}
if ((keysd & KEY_SELECT)) {
if ((keysd & KEY_SELECT)) {
SDL_PrivateJoystickButton(joystick, 6, SDL_PRESSED);
}
if ((keysd & KEY_START)) {
if ((keysd & KEY_START)) {
SDL_PrivateJoystickButton(joystick, 7, SDL_PRESSED);
}
if ((keysu & KEY_A)) {
if ((keysu & KEY_A)) {
SDL_PrivateJoystickButton(joystick, 0, SDL_RELEASED);
}
if ((keysu & KEY_B)) {
if ((keysu & KEY_B)) {
SDL_PrivateJoystickButton(joystick, 1, SDL_RELEASED);
}
if ((keysu & KEY_X)) {
if ((keysu & KEY_X)) {
SDL_PrivateJoystickButton(joystick, 2, SDL_RELEASED);
}
if ((keysu & KEY_Y)) {
if ((keysu & KEY_Y)) {
SDL_PrivateJoystickButton(joystick, 3, SDL_RELEASED);
}
if ((keysu & KEY_L)) {
if ((keysu & KEY_L)) {
SDL_PrivateJoystickButton(joystick, 4, SDL_RELEASED);
}
if ((keysu & KEY_R)) {
if ((keysu & KEY_R)) {
SDL_PrivateJoystickButton(joystick, 5, SDL_RELEASED);
}
if ((keysu & KEY_SELECT)) {
if ((keysu & KEY_SELECT)) {
SDL_PrivateJoystickButton(joystick, 6, SDL_RELEASED);
}
if ((keysu & KEY_START)) {
if ((keysu & KEY_START)) {
SDL_PrivateJoystickButton(joystick, 7, SDL_RELEASED);
}
}
}
/* Function to close a joystick after use */
void
......
......@@ -29,6 +29,21 @@
#define SDL_isupperhex(X) (((X) >= 'A') && ((X) <= 'F'))
#define SDL_islowerhex(X) (((X) >= 'a') && ((X) <= 'f'))
#define UTF8_IsLeadByte(c) ((c) >= 0xC0 && (c) <= 0xF4)
#define UTF8_IsTrailingByte(c) ((c) >= 0x80 && (c) <= 0xBF)
int UTF8_TrailingBytes(unsigned char c)
{
if (c >= 0xC0 && c<= 0xDF)
return 1;
else if (c >= 0xE0 && c <= 0xEF)
return 2;
else if (c >= 0xF0 && c <= 0xF4)
return 3;
else
return 0;
}
#if !defined(HAVE_SSCANF) || !defined(HAVE_STRTOL)
static size_t
SDL_ScanLong(const char *text, int radix, long *valuep)
......@@ -348,6 +363,33 @@ SDL_wcslen(const wchar_t * string)
}
#endif
#ifndef HAVE_WCSLCPY
size_t
SDL_wcslcpy(wchar_t *dst, const wchar_t *src, size_t maxlen)
{
size_t srclen = SDL_wcslen(src);
if (maxlen > 0) {
size_t len = SDL_min(srclen, maxlen - 1);
SDL_memcpy(dst, src, len * sizeof(wchar_t));
dst[len] = '\0';
}
return srclen;
}
#endif
#ifndef HAVE_WCSLCAT
size_t
SDL_wcslcat(wchar_t *dst, const wchar_t *src, size_t maxlen)
{
size_t dstlen = SDL_wcslen(dst);
size_t srclen = SDL_wcslen(src);
if (dstlen < maxlen) {
SDL_wcslcpy(dst + dstlen, src, maxlen - dstlen);
}
return dstlen + srclen;
}
#endif
#ifndef HAVE_STRLCPY
size_t
SDL_strlcpy(char *dst, const char *src, size_t maxlen)
......@@ -362,6 +404,38 @@ SDL_strlcpy(char *dst, const char *src, size_t maxlen)
}
#endif
size_t SDL_utf8strlcpy(char *dst, const char *src, size_t dst_bytes)
{
size_t src_bytes = SDL_strlen(src);
size_t bytes = SDL_min(src_bytes, dst_bytes - 1);
int i = 0;
char trailing_bytes = 0;
if (bytes)
{
unsigned char c = (unsigned char)src[bytes - 1];
if (UTF8_IsLeadByte(c))
--bytes;
else if (UTF8_IsTrailingByte(c))
{
for (i = bytes - 1; i != 0; --i)
{
c = (unsigned char)src[i];
trailing_bytes = UTF8_TrailingBytes(c);
if (trailing_bytes)
{
if (bytes - i != trailing_bytes + 1)
bytes = i;
break;
}
}
}
SDL_memcpy(dst, src, bytes);
}
dst[bytes] = '\0';
return bytes;
}
#ifndef HAVE_STRLCAT
size_t
SDL_strlcat(char *dst, const char *src, size_t maxlen)
......
......@@ -139,6 +139,8 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
}
#endif
if (IME_HandleMessage(hwnd, msg, wParam, &lParam, data->videodata))
return 0;
switch (msg) {
......@@ -605,7 +607,7 @@ SDL_RegisterApp(char *name, Uint32 style, void *hInst)
class.hbrBackground = NULL;
class.hInstance = SDL_Instance;
class.style = SDL_Appstyle;
class.lpfnWndProc = DefWindowProc;
class.lpfnWndProc = WIN_WindowProc;
class.cbWndExtra = 0;
class.cbClsExtra = 0;
if (!RegisterClass(&class)) {
......
......@@ -26,6 +26,14 @@
#include "../../events/SDL_keyboard_c.h"
#include "../../events/scancodes_win32.h"
#include <imm.h>
#include <oleauto.h>
static void IME_Init(SDL_VideoData *videodata, HWND hwnd);
static void IME_Enable(SDL_VideoData *videodata, HWND hwnd);
static void IME_Disable(SDL_VideoData *videodata, HWND hwnd);
static void IME_Quit(SDL_VideoData *videodata);
#ifndef MAPVK_VK_TO_VSC
#define MAPVK_VK_TO_VSC 0
#endif
......@@ -81,6 +89,34 @@ WIN_InitKeyboard(_THIS)
data->key_layout = win32_scancode_table;
data->ime_com_initialized = SDL_FALSE;
data->ime_threadmgr = 0;
data->ime_initialized = SDL_FALSE;
data->ime_enabled = SDL_FALSE;
data->ime_available = SDL_FALSE;
data->ime_hwnd_main = 0;
data->ime_hwnd_current = 0;
data->ime_himc = 0;
data->ime_composition[0] = 0;
data->ime_readingstring[0] = 0;
data->ime_cursor = 0;
data->ime_hkl = 0;
data->ime_himm32 = 0;
data->GetReadingString = 0;
data->ShowReadingWindow = 0;
data->ImmLockIMC = 0;
data->ImmUnlockIMC = 0;
data->ImmLockIMCC = 0;
data->ImmUnlockIMCC = 0;
data->ime_uiless = SDL_FALSE;
data->ime_threadmgrex = 0;
data->ime_uielemsinkcookie = TF_INVALID_COOKIE;
data->ime_alpnsinkcookie = TF_INVALID_COOKIE;
data->ime_openmodesinkcookie = TF_INVALID_COOKIE;
data->ime_convmodesinkcookie = TF_INVALID_COOKIE;
data->ime_uielemsink = 0;
data->ime_ippasink = 0;
WIN_UpdateKeymap();
SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu");
......@@ -119,6 +155,851 @@ WIN_UpdateKeymap()
void
WIN_QuitKeyboard(_THIS)
{
IME_Quit((SDL_VideoData *)_this->driverdata);
}
void
WIN_StartTextInput(_THIS)
{
SDL_Window *window = SDL_GetKeyboardFocus();
if (window) {
HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
IME_Init(videodata, hwnd);
IME_Enable(videodata, hwnd);
}
}
void
WIN_StopTextInput(_THIS)
{
SDL_Window *window = SDL_GetKeyboardFocus();
if (window) {
HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
IME_Init(videodata, hwnd);
IME_Disable(videodata, hwnd);
}
}
void
WIN_SetTextInputRect(_THIS, SDL_Rect *rect)
{
}
#define LANG_CHT MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)
#define LANG_CHS MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED)
#define MAKEIMEVERSION(major,minor) ((DWORD) (((BYTE)(major) << 24) | ((BYTE)(minor) << 16) ))
#define IMEID_VER(id) ((id) & 0xffff0000)
#define IMEID_LANG(id) ((id) & 0x0000ffff)
#define CHT_HKL_DAYI ((HKL)0xE0060404)
#define CHT_HKL_NEW_PHONETIC ((HKL)0xE0080404)
#define CHT_HKL_NEW_CHANG_JIE ((HKL)0xE0090404)
#define CHT_HKL_NEW_QUICK ((HKL)0xE00A0404)
#define CHT_HKL_HK_CANTONESE ((HKL)0xE00B0404)
#define CHT_IMEFILENAME1 "TINTLGNT.IME"
#define CHT_IMEFILENAME2 "CINTLGNT.IME"
#define CHT_IMEFILENAME3 "MSTCIPHA.IME"
#define IMEID_CHT_VER42 (LANG_CHT | MAKEIMEVERSION(4, 2))
#define IMEID_CHT_VER43 (LANG_CHT | MAKEIMEVERSION(4, 3))
#define IMEID_CHT_VER44 (LANG_CHT | MAKEIMEVERSION(4, 4))
#define IMEID_CHT_VER50 (LANG_CHT | MAKEIMEVERSION(5, 0))
#define IMEID_CHT_VER51 (LANG_CHT | MAKEIMEVERSION(5, 1))
#define IMEID_CHT_VER52 (LANG_CHT | MAKEIMEVERSION(5, 2))
#define IMEID_CHT_VER60 (LANG_CHT | MAKEIMEVERSION(6, 0))
#define IMEID_CHT_VER_VISTA (LANG_CHT | MAKEIMEVERSION(7, 0))
#define CHS_HKL ((HKL)0xE00E0804)
#define CHS_IMEFILENAME1 "PINTLGNT.IME"
#define CHS_IMEFILENAME2 "MSSCIPYA.IME"
#define IMEID_CHS_VER41 (LANG_CHS | MAKEIMEVERSION(4, 1))
#define IMEID_CHS_VER42 (LANG_CHS | MAKEIMEVERSION(4, 2))
#define IMEID_CHS_VER53 (LANG_CHS | MAKEIMEVERSION(5, 3))
#define LANG() LOWORD((videodata->ime_hkl))
#define PRIMLANG() ((WORD)PRIMARYLANGID(LANG()))
#define SUBLANG() SUBLANGID(LANG())
static void IME_UpdateInputLocale(SDL_VideoData *videodata);
static void IME_ClearComposition(SDL_VideoData *videodata);
static void IME_SetWindow(SDL_VideoData* videodata, HWND hwnd);
static void IME_SetupAPI(SDL_VideoData *videodata);
static DWORD IME_GetId(SDL_VideoData *videodata, UINT uIndex);
static void IME_SendEditingEvent(SDL_VideoData *videodata);
#define SDL_IsEqualIID(riid1, riid2) SDL_IsEqualGUID(riid1, riid2)
#define SDL_IsEqualGUID(rguid1, rguid2) (!SDL_memcmp(rguid1, rguid2, sizeof(GUID)))
static SDL_bool UILess_SetupSinks(SDL_VideoData *videodata);
static void UILess_ReleaseSinks(SDL_VideoData *videodata);
static void UILess_EnableUIUpdates(SDL_VideoData *videodata);
static void UILess_DisableUIUpdates(SDL_VideoData *videodata);
static void
IME_Init(SDL_VideoData *videodata, HWND hwnd)
{
if (videodata->ime_initialized)
return;
videodata->ime_hwnd_main = hwnd;
if (SUCCEEDED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) {
videodata->ime_com_initialized = SDL_TRUE;
CoCreateInstance(&CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, &IID_ITfThreadMgr, &videodata->ime_threadmgr);
}
videodata->ime_initialized = SDL_TRUE;
videodata->ime_himm32 = LoadLibraryA("imm32.dll");
if (!videodata->ime_himm32) {
videodata->ime_available = SDL_FALSE;
return;
}
videodata->ImmLockIMC = (LPINPUTCONTEXT2 (WINAPI *)(HIMC))GetProcAddress(videodata->ime_himm32, "ImmLockIMC");
videodata->ImmUnlockIMC = (BOOL (WINAPI *)(HIMC))GetProcAddress(videodata->ime_himm32, "ImmUnlockIMC");
videodata->ImmLockIMCC = (LPVOID (WINAPI *)(HIMCC))GetProcAddress(videodata->ime_himm32, "ImmLockIMCC");
videodata->ImmUnlockIMCC = (BOOL (WINAPI *)(HIMCC))GetProcAddress(videodata->ime_himm32, "ImmUnlockIMCC");
IME_SetWindow(videodata, hwnd);
videodata->ime_himc = ImmGetContext(hwnd);
ImmReleaseContext(hwnd, videodata->ime_himc);
if (!videodata->ime_himc) {
videodata->ime_available = SDL_FALSE;
IME_Disable(videodata, hwnd);
return;
}
videodata->ime_available = SDL_TRUE;
IME_UpdateInputLocale(videodata);
IME_SetupAPI(videodata);
videodata->ime_uiless = UILess_SetupSinks(videodata);
IME_UpdateInputLocale(videodata);
IME_Disable(videodata, hwnd);
}
static void
IME_Enable(SDL_VideoData *videodata, HWND hwnd)
{
if (!videodata->ime_initialized || !videodata->ime_hwnd_current)
return;
if (!videodata->ime_available) {
IME_Disable(videodata, hwnd);
return;
}
if (videodata->ime_hwnd_current == videodata->ime_hwnd_main)
ImmAssociateContext(videodata->ime_hwnd_current, videodata->ime_himc);
videodata->ime_enabled = SDL_TRUE;
IME_UpdateInputLocale(videodata);
UILess_EnableUIUpdates(videodata);
}
static void
IME_Disable(SDL_VideoData *videodata, HWND hwnd)
{
if (!videodata->ime_initialized || !videodata->ime_hwnd_current)
return;
IME_ClearComposition(videodata);
if (videodata->ime_hwnd_current == videodata->ime_hwnd_main)
ImmAssociateContext(videodata->ime_hwnd_current, NULL);
videodata->ime_enabled = SDL_FALSE;
UILess_DisableUIUpdates(videodata);
}
static void
IME_Quit(SDL_VideoData *videodata)
{
if (!videodata->ime_initialized)
return;
UILess_ReleaseSinks(videodata);
if (videodata->ime_hwnd_main)
ImmAssociateContext(videodata->ime_hwnd_main, videodata->ime_himc);
videodata->ime_hwnd_main = 0;
videodata->ime_himc = 0;
if (videodata->ime_himm32) {
FreeLibrary(videodata->ime_himm32);
videodata->ime_himm32 = 0;
}
if (videodata->ime_threadmgr) {
videodata->ime_threadmgr->lpVtbl->Release(videodata->ime_threadmgr);
videodata->ime_threadmgr = 0;
}
if (videodata->ime_com_initialized) {
CoUninitialize();
videodata->ime_com_initialized = SDL_FALSE;
}
videodata->ime_initialized = SDL_FALSE;
}
static void
IME_GetReadingString(SDL_VideoData *videodata, HWND hwnd)
{
DWORD id = 0;
HIMC himc = 0;
WCHAR buffer[16];
WCHAR *s = buffer;
DWORD len = 0;
DWORD err = 0;
BOOL vertical = FALSE;
UINT maxuilen = 0;
static OSVERSIONINFOA osversion = {0};
if (videodata->ime_uiless)
return;
videodata->ime_readingstring[0] = 0;
if (!osversion.dwOSVersionInfoSize) {
osversion.dwOSVersionInfoSize = sizeof(osversion);
GetVersionExA(&osversion);
}
id = IME_GetId(videodata, 0);
if (!id)
return;
himc = ImmGetContext(hwnd);
if (!himc)
return;
if (videodata->GetReadingString) {
len = videodata->GetReadingString(himc, 0, 0, &err, &vertical, &maxuilen);
if (len) {
if (len > SDL_arraysize(buffer))
len = SDL_arraysize(buffer);
len = videodata->GetReadingString(himc, len, s, &err, &vertical, &maxuilen);
}
SDL_wcslcpy(videodata->ime_readingstring, s, len);
}
else {
LPINPUTCONTEXT2 lpimc = videodata->ImmLockIMC(himc);
LPBYTE p = 0;
s = 0;
switch (id)
{
case IMEID_CHT_VER42:
case IMEID_CHT_VER43:
case IMEID_CHT_VER44:
p = *(LPBYTE *)((LPBYTE)videodata->ImmLockIMCC(lpimc->hPrivate) + 24);
if (!p)
break;
len = *(DWORD *)(p + 7*4 + 32*4);
s = (WCHAR *)(p + 56);
break;
case IMEID_CHT_VER51:
case IMEID_CHT_VER52:
case IMEID_CHS_VER53:
p = *(LPBYTE *)((LPBYTE)videodata->ImmLockIMCC(lpimc->hPrivate) + 4);
if (!p)
break;
p = *(LPBYTE *)((LPBYTE)p + 1*4 + 5*4);
if (!p)
break;
len = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16*2);
s = (WCHAR *)(p + 1*4 + (16*2+2*4) + 5*4);
break;
case IMEID_CHS_VER41:
{
int offset = (IME_GetId(videodata, 1) >= 0x00000002) ? 8 : 7;
p = *(LPBYTE *)((LPBYTE)videodata->ImmLockIMCC(lpimc->hPrivate) + offset * 4);
if (!p)
break;
len = *(DWORD *)(p + 7*4 + 16*2*4);
s = (WCHAR *)(p + 6*4 + 16*2*1);
}
break;
case IMEID_CHS_VER42:
if (osversion.dwPlatformId != VER_PLATFORM_WIN32_NT)
break;
p = *(LPBYTE *)((LPBYTE)videodata->ImmLockIMCC(lpimc->hPrivate) + 1*4 + 1*4 + 6*4);
if (!p)
break;
len = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16*2);
s = (WCHAR *)(p + 1*4 + (16*2+2*4) + 5*4);
break;
}
if (s)
SDL_wcslcpy(videodata->ime_readingstring, s, len + 1);
videodata->ImmUnlockIMCC(lpimc->hPrivate);
videodata->ImmUnlockIMC(himc);
}
ImmReleaseContext(hwnd, himc);
IME_SendEditingEvent(videodata);
}
static void
IME_InputLangChanged(SDL_VideoData *videodata)
{
UINT lang = PRIMLANG();
HWND hwndime = 0;
IME_UpdateInputLocale(videodata);
IME_SetupAPI(videodata);
if (lang != PRIMLANG()) {
IME_ClearComposition(videodata);
}
hwndime = ImmGetDefaultIMEWnd(videodata->ime_hwnd_current);
if (hwndime) {
SendMessageA(hwndime, WM_IME_CONTROL, IMC_OPENSTATUSWINDOW, 0);
SendMessageA(hwndime, WM_IME_CONTROL, IMC_CLOSESTATUSWINDOW, 0);
}
}
static DWORD
IME_GetId(SDL_VideoData *videodata, UINT uIndex)
{
static HKL hklprev = 0;
static DWORD dwRet[2] = {0};
DWORD dwVerSize = 0;
DWORD dwVerHandle = 0;
LPVOID lpVerBuffer = 0;
LPVOID lpVerData = 0;
UINT cbVerData = 0;
char szTemp[256];
HKL hkl = 0;
DWORD dwLang = 0;
if (uIndex >= sizeof(dwRet) / sizeof(dwRet[0]))
return 0;
hkl = videodata->ime_hkl;
if (hklprev == hkl)
return dwRet[uIndex];
hklprev = hkl;
dwLang = ((DWORD)hkl & 0xffff);
if (videodata->ime_uiless && LANG() == LANG_CHT) {
dwRet[0] = IMEID_CHT_VER_VISTA;
dwRet[1] = 0;
return dwRet[0];
}
if (hkl != CHT_HKL_NEW_PHONETIC
&& hkl != CHT_HKL_NEW_CHANG_JIE
&& hkl != CHT_HKL_NEW_QUICK
&& hkl != CHT_HKL_HK_CANTONESE
&& hkl != CHS_HKL) {
dwRet[0] = dwRet[1] = 0;
return dwRet[uIndex];
}
if (ImmGetIMEFileNameA(hkl, szTemp, sizeof(szTemp) - 1) <= 0) {
dwRet[0] = dwRet[1] = 0;
return dwRet[uIndex];
}
if (!videodata->GetReadingString) {
#define LCID_INVARIANT MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT)
if (CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHT_IMEFILENAME1, -1) != 2
&& CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHT_IMEFILENAME2, -1) != 2
&& CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHT_IMEFILENAME3, -1) != 2
&& CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHS_IMEFILENAME1, -1) != 2
&& CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHS_IMEFILENAME2, -1) != 2) {
dwRet[0] = dwRet[1] = 0;
return dwRet[uIndex];
}
#undef LCID_INVARIANT
dwVerSize = GetFileVersionInfoSizeA(szTemp, &dwVerHandle);
if (dwVerSize) {
lpVerBuffer = SDL_malloc(dwVerSize);
if (lpVerBuffer) {
if (GetFileVersionInfoA(szTemp, dwVerHandle, dwVerSize, lpVerBuffer)) {
if (VerQueryValueA(lpVerBuffer, "\\", &lpVerData, &cbVerData)) {
#define pVerFixedInfo ((VS_FIXEDFILEINFO FAR*)lpVerData)
DWORD dwVer = pVerFixedInfo->dwFileVersionMS;
dwVer = (dwVer & 0x00ff0000) << 8 | (dwVer & 0x000000ff) << 16;
if (videodata->GetReadingString ||
dwLang == LANG_CHT && (
dwVer == MAKEIMEVERSION(4, 2) ||
dwVer == MAKEIMEVERSION(4, 3) ||
dwVer == MAKEIMEVERSION(4, 4) ||
dwVer == MAKEIMEVERSION(5, 0) ||
dwVer == MAKEIMEVERSION(5, 1) ||
dwVer == MAKEIMEVERSION(5, 2) ||
dwVer == MAKEIMEVERSION(6, 0))
||
dwLang == LANG_CHS && (
dwVer == MAKEIMEVERSION(4, 1) ||
dwVer == MAKEIMEVERSION(4, 2) ||
dwVer == MAKEIMEVERSION(5, 3))) {
dwRet[0] = dwVer | dwLang;
dwRet[1] = pVerFixedInfo->dwFileVersionLS;
SDL_free(lpVerBuffer);
return dwRet[0];
}
#undef pVerFixedInfo
}
}
}
SDL_free(lpVerBuffer);
}
}
dwRet[0] = dwRet[1] = 0;
return dwRet[uIndex];
}
static void
IME_SetupAPI(SDL_VideoData *videodata)
{
char ime_file[MAX_PATH + 1];
HMODULE hime = 0;
HKL hkl = 0;
videodata->GetReadingString = 0;
videodata->ShowReadingWindow = 0;
if (videodata->ime_uiless)
return;
hkl = videodata->ime_hkl;
if (ImmGetIMEFileNameA(hkl, ime_file, sizeof(ime_file) - 1) <= 0)
return;
hime = LoadLibraryA(ime_file);
if (!hime)
return;
videodata->GetReadingString = (UINT (WINAPI *)(HIMC, UINT, LPWSTR, PINT, BOOL*, PUINT))
GetProcAddress(hime, "GetReadingString");
videodata->ShowReadingWindow = (BOOL (WINAPI *)(HIMC, BOOL))
GetProcAddress(hime, "ShowReadingWindow");
if (videodata->ShowReadingWindow) {
HIMC himc = ImmGetContext(videodata->ime_hwnd_current);
if (himc) {
videodata->ShowReadingWindow(himc, FALSE);
ImmReleaseContext(videodata->ime_hwnd_current, himc);
}
}
}
static void
IME_SetWindow(SDL_VideoData* videodata, HWND hwnd)
{
videodata->ime_hwnd_current = hwnd;
if (videodata->ime_threadmgr) {
struct ITfDocumentMgr *document_mgr = 0;
if (SUCCEEDED(videodata->ime_threadmgr->lpVtbl->AssociateFocus(videodata->ime_threadmgr, hwnd, NULL, &document_mgr))) {
if (document_mgr)
document_mgr->lpVtbl->Release(document_mgr);
}
}
}
static void
IME_UpdateInputLocale(SDL_VideoData *videodata)
{
static HKL hklprev = 0;
videodata->ime_hkl = GetKeyboardLayout(0);
if (hklprev == videodata->ime_hkl)
return;
hklprev = videodata->ime_hkl;
}
static void
IME_ClearComposition(SDL_VideoData *videodata)
{
HIMC himc = 0;
if (!videodata->ime_initialized)
return;
himc = ImmGetContext(videodata->ime_hwnd_current);
if (!himc)
return;
ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
if (videodata->ime_uiless)
ImmSetCompositionString(himc, SCS_SETSTR, TEXT(""), sizeof(TCHAR), TEXT(""), sizeof(TCHAR));
ImmNotifyIME(himc, NI_CLOSECANDIDATE, 0, 0);
ImmReleaseContext(videodata->ime_hwnd_current, himc);
SDL_SendEditingText("", 0, 0);
}
static void
IME_ClearEditing(SDL_VideoData *videodata)
{
}
static void
IME_GetCompositionString(SDL_VideoData *videodata, HIMC himc, DWORD string)
{
LONG length = ImmGetCompositionStringW(himc, string, videodata->ime_composition, sizeof(videodata->ime_composition));
if (length < 0)
length = 0;
length /= sizeof(videodata->ime_composition[0]);
videodata->ime_cursor = LOWORD(ImmGetCompositionStringW(himc, GCS_CURSORPOS, 0, 0));
if (videodata->ime_composition[videodata->ime_cursor] == 0x3000) {
int i;
for (i = videodata->ime_cursor + 1; i < length; ++i)
videodata->ime_composition[i - 1] = videodata->ime_composition[i];
--length;
}
videodata->ime_composition[length] = 0;
}
static void
IME_SendInputEvent(SDL_VideoData *videodata)
{
char *s = 0;
s = WIN_StringToUTF8(videodata->ime_composition);
SDL_SendKeyboardText(s);
SDL_free(s);
videodata->ime_composition[0] = 0;
videodata->ime_readingstring[0] = 0;
videodata->ime_cursor = 0;
}
static void
IME_SendEditingEvent(SDL_VideoData *videodata)
{
char *s = 0;
WCHAR buffer[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
buffer[0] = 0;
if (videodata->ime_readingstring[0]) {
size_t len = SDL_min(SDL_wcslen(videodata->ime_composition), (size_t)videodata->ime_cursor);
SDL_wcslcpy(buffer, videodata->ime_composition, len + 1);
SDL_wcslcat(buffer, videodata->ime_readingstring, sizeof(buffer));
SDL_wcslcat(buffer, &videodata->ime_composition[len], sizeof(buffer) - len);
}
else {
SDL_wcslcpy(buffer, videodata->ime_composition, sizeof(videodata->ime_composition));
}
s = WIN_StringToUTF8(buffer);
SDL_SendEditingText(s, videodata->ime_cursor + SDL_wcslen(videodata->ime_readingstring), 0);
SDL_free(s);
}
SDL_bool
IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoData *videodata)
{
SDL_bool trap = SDL_FALSE;
HIMC himc = 0;
if (!videodata->ime_initialized || !videodata->ime_available || !videodata->ime_enabled)
return SDL_FALSE;
switch (msg)
{
case WM_INPUTLANGCHANGE:
//IME_InputLangChanged(videodata);
break;
case WM_IME_SETCONTEXT:
*lParam = 0;
break;
case WM_IME_STARTCOMPOSITION:
trap = SDL_TRUE;
break;
case WM_IME_COMPOSITION:
trap = SDL_TRUE;
himc = ImmGetContext(hwnd);
if (*lParam & GCS_RESULTSTR) {
IME_GetCompositionString(videodata, himc, GCS_RESULTSTR);
IME_SendInputEvent(videodata);
}
if (*lParam & GCS_COMPSTR) {
if (!videodata->ime_uiless)
videodata->ime_readingstring[0] = 0;
IME_GetCompositionString(videodata, himc, GCS_COMPSTR);
IME_SendEditingEvent(videodata);
}
ImmReleaseContext(hwnd, himc);
break;
case WM_IME_ENDCOMPOSITION:
videodata->ime_composition[0] = 0;
videodata->ime_readingstring[0] = 0;
videodata->ime_cursor = 0;
SDL_SendEditingText("", 0, 0);
break;
case WM_IME_NOTIFY:
switch (wParam)
{
case IMN_SETCONVERSIONMODE:
case IMN_SETOPENSTATUS:
IME_UpdateInputLocale(videodata);
break;
case IMN_OPENCANDIDATE:
case IMN_CHANGECANDIDATE:
trap = SDL_TRUE;
break;
case IMN_CLOSECANDIDATE:
trap = SDL_TRUE;
break;
case IMN_PRIVATE:
{
DWORD dwId = IME_GetId(videodata, 0);
IME_GetReadingString(videodata, hwnd);
switch (dwId)
{
case IMEID_CHT_VER42:
case IMEID_CHT_VER43:
case IMEID_CHT_VER44:
case IMEID_CHS_VER41:
case IMEID_CHS_VER42:
if (*lParam == 1 || *lParam == 2)
trap = SDL_TRUE;
break;
case IMEID_CHT_VER50:
case IMEID_CHT_VER51:
case IMEID_CHT_VER52:
case IMEID_CHT_VER60:
case IMEID_CHS_VER53:
if (*lParam == 16
|| *lParam == 17
|| *lParam == 26
|| *lParam == 27
|| *lParam == 28)
trap = SDL_TRUE;
break;
}
}
break;
default:
trap = SDL_TRUE;
break;
}
break;
}
return trap;
}
STDMETHODIMP_(ULONG) TSFSink_AddRef(TSFSink *sink)
{
return ++sink->refcount;
}
STDMETHODIMP_(ULONG)TSFSink_Release(TSFSink *sink)
{
--sink->refcount;
if (sink->refcount == 0)
{
SDL_free(sink);
return 0;
}
return sink->refcount;
}
STDMETHODIMP UIElementSink_QueryInterface(TSFSink *sink, REFIID riid, PVOID *ppv)
{
if (!ppv)
return E_INVALIDARG;
*ppv = 0;
if (SDL_IsEqualIID(riid, &IID_IUnknown))
*ppv = (IUnknown *)sink;
else if (SDL_IsEqualIID(riid, &IID_ITfUIElementSink))
*ppv = (ITfUIElementSink *)sink;
if (*ppv) {
TSFSink_AddRef(sink);
return S_OK;
}
return E_NOINTERFACE;
}
ITfUIElement *UILess_GetUIElement(SDL_VideoData *videodata, DWORD dwUIElementId)
{
ITfUIElementMgr *puiem = 0;
ITfUIElement *pelem = 0;
ITfThreadMgrEx *threadmgrex = videodata->ime_threadmgrex;
if (SUCCEEDED(threadmgrex->lpVtbl->QueryInterface(threadmgrex, &IID_ITfUIElementMgr, (LPVOID *)&puiem))) {
puiem->lpVtbl->GetUIElement(puiem, dwUIElementId, &pelem);
puiem->lpVtbl->Release(puiem);
}
return pelem;
}
STDMETHODIMP UIElementSink_BeginUIElement(TSFSink *sink, DWORD dwUIElementId, BOOL *pbShow)
{
ITfUIElement *element = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId);
ITfReadingInformationUIElement *preading = 0;
SDL_VideoData *videodata = (SDL_VideoData *)sink->data;
if (!element)
return E_INVALIDARG;
*pbShow = FALSE;
if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfReadingInformationUIElement, (LPVOID *)&preading))) {
BSTR bstr;
if (SUCCEEDED(preading->lpVtbl->GetString(preading, &bstr)) && bstr) {
WCHAR *s = (WCHAR *)bstr;
SysFreeString(bstr);
}
preading->lpVtbl->Release(preading);
}
return S_OK;
}
STDMETHODIMP UIElementSink_UpdateUIElement(TSFSink *sink, DWORD dwUIElementId)
{
ITfUIElement *element = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId);
ITfReadingInformationUIElement *preading = 0;
SDL_VideoData *videodata = (SDL_VideoData *)sink->data;
if (!element)
return E_INVALIDARG;
if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfReadingInformationUIElement, (LPVOID *)&preading))) {
BSTR bstr;
if (SUCCEEDED(preading->lpVtbl->GetString(preading, &bstr)) && bstr) {
WCHAR *s = (WCHAR *)bstr;
SDL_wcslcpy(videodata->ime_readingstring, s, sizeof(videodata->ime_readingstring));
IME_SendEditingEvent(videodata);
SysFreeString(bstr);
}
preading->lpVtbl->Release(preading);
}
return S_OK;
}
STDMETHODIMP UIElementSink_EndUIElement(TSFSink *sink, DWORD dwUIElementId)
{
ITfUIElement *element = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId);
ITfReadingInformationUIElement *preading = 0;
SDL_VideoData *videodata = (SDL_VideoData *)sink->data;
if (!element)
return E_INVALIDARG;
if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfReadingInformationUIElement, (LPVOID *)&preading))) {
videodata->ime_readingstring[0] = 0;
IME_SendEditingEvent(videodata);
preading->lpVtbl->Release(preading);
}
return S_OK;
}
STDMETHODIMP IPPASink_QueryInterface(TSFSink *sink, REFIID riid, PVOID *ppv)
{
if (!ppv)
return E_INVALIDARG;
*ppv = 0;
if (SDL_IsEqualIID(riid, &IID_IUnknown))
*ppv = (IUnknown *)sink;
else if (SDL_IsEqualIID(riid, &IID_ITfInputProcessorProfileActivationSink))
*ppv = (ITfInputProcessorProfileActivationSink *)sink;
if (*ppv) {
TSFSink_AddRef(sink);
return S_OK;
}
return E_NOINTERFACE;
}
STDMETHODIMP IPPASink_OnActivated(TSFSink *sink, DWORD dwProfileType, LANGID langid, REFCLSID clsid, REFGUID catid, REFGUID guidProfile, HKL hkl, DWORD dwFlags)
{
if (SDL_IsEqualIID(catid, &GUID_TFCAT_TIP_KEYBOARD) && (dwFlags & TF_IPSINK_FLAG_ACTIVE))
IME_InputLangChanged((SDL_VideoData *)sink->data);
return S_OK;
}
static void *vtUIElementSink[] = {
(void *)(UIElementSink_QueryInterface),
(void *)(TSFSink_AddRef),
(void *)(TSFSink_Release),
(void *)(UIElementSink_BeginUIElement),
(void *)(UIElementSink_UpdateUIElement),
(void *)(UIElementSink_EndUIElement)
};
static void *vtIPPASink[] = {
(void *)(IPPASink_QueryInterface),
(void *)(TSFSink_AddRef),
(void *)(TSFSink_Release),
(void *)(IPPASink_OnActivated)
};
static void
UILess_EnableUIUpdates(SDL_VideoData *videodata)
{
ITfSource *source = 0;
if (!videodata->ime_threadmgrex || videodata->ime_uielemsinkcookie != TF_INVALID_COOKIE)
return;
if (SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, (LPVOID *)&source))) {
source->lpVtbl->AdviseSink(source, &IID_ITfUIElementSink, (IUnknown *)videodata->ime_uielemsink, &videodata->ime_uielemsinkcookie);
source->lpVtbl->Release(source);
}
}
static void
UILess_DisableUIUpdates(SDL_VideoData *videodata)
{
ITfSource *source = 0;
if (!videodata->ime_threadmgrex || videodata->ime_uielemsinkcookie == TF_INVALID_COOKIE)
return;
if (SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, (LPVOID *)&source))) {
source->lpVtbl->UnadviseSink(source, videodata->ime_uielemsinkcookie);
videodata->ime_uielemsinkcookie = TF_INVALID_COOKIE;
source->lpVtbl->Release(source);
}
}
static SDL_bool
UILess_SetupSinks(SDL_VideoData *videodata)
{
TfClientId clientid = 0;
SDL_bool result = SDL_FALSE;
ITfSource *source = 0;
if (FAILED(CoCreateInstance(&CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, &IID_ITfThreadMgrEx, &videodata->ime_threadmgrex)))
return SDL_FALSE;
if (FAILED(videodata->ime_threadmgrex->lpVtbl->ActivateEx(videodata->ime_threadmgrex, &clientid, TF_TMAE_UIELEMENTENABLEDONLY)))
return SDL_FALSE;
videodata->ime_uielemsink = SDL_malloc(sizeof(TSFSink));
videodata->ime_ippasink = SDL_malloc(sizeof(TSFSink));
videodata->ime_uielemsink->lpVtbl = vtUIElementSink;
videodata->ime_uielemsink->refcount = 1;
videodata->ime_uielemsink->data = videodata;
videodata->ime_ippasink->lpVtbl = vtIPPASink;
videodata->ime_ippasink->refcount = 1;
videodata->ime_ippasink->data = videodata;
if (SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, (LPVOID *)&source))) {
if (SUCCEEDED(source->lpVtbl->AdviseSink(source, &IID_ITfUIElementSink, (IUnknown *)videodata->ime_uielemsink, &videodata->ime_uielemsinkcookie))) {
if (SUCCEEDED(source->lpVtbl->AdviseSink(source, &IID_ITfInputProcessorProfileActivationSink, (IUnknown *)videodata->ime_ippasink, &videodata->ime_alpnsinkcookie))) {
result = SDL_TRUE;
}
}
source->lpVtbl->Release(source);
}
return result;
}
#define SAFE_RELEASE(p) \
{ \
if (p) { \
(p)->lpVtbl->Release((p)); \
(p) = 0; \
} \
}
static void
UILess_ReleaseSinks(SDL_VideoData *videodata)
{
ITfSource *source = 0;
if (videodata->ime_threadmgrex && SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, &source))) {
source->lpVtbl->UnadviseSink(source, videodata->ime_uielemsinkcookie);
source->lpVtbl->UnadviseSink(source, videodata->ime_alpnsinkcookie);
SAFE_RELEASE(source);
videodata->ime_threadmgrex->lpVtbl->Deactivate(videodata->ime_threadmgrex);
SAFE_RELEASE(videodata->ime_threadmgrex);
TSFSink_Release(videodata->ime_uielemsink);
videodata->ime_uielemsink = 0;
TSFSink_Release(videodata->ime_ippasink);
videodata->ime_ippasink = 0;
}
}
/* vi: set ts=4 sw=4 expandtab: */
......@@ -31,6 +31,12 @@ extern void WIN_InitKeyboard(_THIS);
extern void WIN_UpdateKeymap(void);
extern void WIN_QuitKeyboard(_THIS);
extern void WIN_StartTextInput(_THIS);
extern void WIN_StopTextInput(_THIS);
extern void WIN_SetTextInputRect(_THIS, SDL_Rect *rect);
extern SDL_bool IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, struct SDL_VideoData *videodata);
#endif /* _SDL_win32keyboard_h */
/* vi: set ts=4 sw=4 expandtab: */
......@@ -191,6 +191,9 @@ WIN_CreateDevice(int devindex)
device->GL_SwapWindow = WIN_GL_SwapWindow;
device->GL_DeleteContext = WIN_GL_DeleteContext;
#endif
device->StartTextInput = WIN_StartTextInput;
device->StopTextInput = WIN_StopTextInput;
device->SetTextInputRect = WIN_SetTextInputRect;
device->SetClipboardText = WIN_SetClipboardText;
device->GetClipboardText = WIN_GetClipboardText;
......
......@@ -42,6 +42,8 @@
#include <windows.h>
#include <msctf.h>
#if SDL_VIDEO_RENDER_D3D
//#include <d3d9.h>
#define D3D_DEBUG_INFO
......@@ -62,6 +64,7 @@
#include "SDL_win32mouse.h"
#include "SDL_win32opengl.h"
#include "SDL_win32window.h"
#include "SDL_events.h"
#ifdef UNICODE
#define WIN_StringToUTF8(S) SDL_iconv_string("UTF-8", "UCS-2", (char *)S, (SDL_wcslen(S)+1)*sizeof(WCHAR))
......@@ -77,6 +80,37 @@ enum { RENDER_NONE, RENDER_D3D, RENDER_DDRAW, RENDER_GDI, RENDER_GAPI, RENDER_RA
typedef BOOL (*PFNSHFullScreen)(HWND, DWORD);
typedef void (*PFCoordTransform)(SDL_Window*, POINT*);
typedef struct
{
void **lpVtbl;
int refcount;
void *data;
} TSFSink;
// Definition from Win98DDK version of IMM.H
typedef struct tagINPUTCONTEXT2 {
HWND hWnd;
BOOL fOpen;
POINT ptStatusWndPos;
POINT ptSoftKbdPos;
DWORD fdwConversion;
DWORD fdwSentence;
union {
LOGFONTA A;
LOGFONTW W;
} lfFont;
COMPOSITIONFORM cfCompForm;
CANDIDATEFORM cfCandForm[4];
HIMCC hCompStr;
HIMCC hCandInfo;
HIMCC hGuideLine;
HIMCC hPrivate;
DWORD dwNumMsgBuf;
HIMCC hMsgBuf;
DWORD fdwInit;
DWORD dwReserve[3];
} INPUTCONTEXT2, *PINPUTCONTEXT2, NEAR *NPINPUTCONTEXT2, FAR *LPINPUTCONTEXT2;
/* Private display data */
typedef struct SDL_VideoData
......@@ -97,9 +131,39 @@ typedef struct SDL_VideoData
PFCoordTransform CoordTransform;
#endif
const SDL_scancode *key_layout;
DWORD clipboard_count;
const SDL_scancode *key_layout;
SDL_bool ime_com_initialized;
struct ITfThreadMgr *ime_threadmgr;
SDL_bool ime_initialized;
SDL_bool ime_enabled;
SDL_bool ime_available;
HWND ime_hwnd_main;
HWND ime_hwnd_current;
HIMC ime_himc;
WCHAR ime_composition[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
WCHAR ime_readingstring[16];
int ime_cursor;
HKL ime_hkl;
HMODULE ime_himm32;
UINT (WINAPI *GetReadingString)(HIMC himc, UINT uReadingBufLen, LPWSTR lpwReadingBuf, PINT pnErrorIndex, BOOL *pfIsVertical, PUINT puMaxReadingLen);
BOOL (WINAPI *ShowReadingWindow)(HIMC himc, BOOL bShow);
LPINPUTCONTEXT2 (WINAPI *ImmLockIMC)(HIMC himc);
BOOL (WINAPI *ImmUnlockIMC)(HIMC himc);
LPVOID (WINAPI *ImmLockIMCC)(HIMCC himcc);
BOOL (WINAPI *ImmUnlockIMCC)(HIMCC himcc);
SDL_bool ime_uiless;
struct ITfThreadMgrEx *ime_threadmgrex;
DWORD ime_uielemsinkcookie;
DWORD ime_alpnsinkcookie;
DWORD ime_openmodesinkcookie;
DWORD ime_convmodesinkcookie;
TSFSink *ime_uielemsink;
TSFSink *ime_ippasink;
} SDL_VideoData;
#endif /* _SDL_win32video_h */
......
......@@ -77,10 +77,12 @@ SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, SDL_bool created)
/* Set up the window proc function */
data->wndproc = (WNDPROC) GetWindowLongPtr(hwnd, GWLP_WNDPROC);
if (data->wndproc == DefWindowProc) {
if (data->wndproc == WIN_WindowProc) {
data->wndproc = NULL;
}
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) WIN_WindowProc);
else {
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) WIN_WindowProc);
}
/* Fill in the SDL window with the window data */
{
......
......@@ -25,7 +25,49 @@ TTF_Font *font;
SDL_Rect textRect, markedRect;
Uint32 lineColor, backColor;
SDL_Color textColor = { 0, 0, 0 };
char text[MAX_TEXT_LENGTH], *markedText;
char text[MAX_TEXT_LENGTH], markedText[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
int cursor = 0;
size_t utf8_length(unsigned char c)
{
c = (unsigned char)(0xff & c);
if (c < 0x80)
return 1;
else if ((c >> 5) ==0x6)
return 2;
else if ((c >> 4) == 0xe)
return 3;
else if ((c >> 3) == 0x1e)
return 4;
else
return 0;
}
char *utf8_next(char *p)
{
size_t len = utf8_length(*p);
size_t i = 0;
if (!len)
return 0;
for (; i < len; ++i)
{
++p;
if (!*p)
return 0;
}
return p;
}
char *utf8_advance(char *p, size_t distance)
{
size_t i = 0;
for (; i < distance && p; ++i)
{
p = utf8_next(p);
}
return p;
}
void usage()
{
......@@ -124,7 +166,7 @@ void InitInput()
text[0] = 0;
markedRect = textRect;
markedText = NULL;
markedText[0] = 0;
SDL_StartTextInput();
}
......@@ -180,9 +222,22 @@ void Redraw()
cursorRect.h = h;
SDL_FillRect(screen, &markedRect, backColor);
if (markedText)
if (markedText[0])
{
#ifdef HAVE_SDL_TTF
if (cursor)
{
char *p = utf8_advance(markedText, cursor);
char c = 0;
if (!p)
p = &markedText[strlen(markedText)];
c = *p;
*p = 0;
TTF_SizeUTF8(font, markedText, &w, 0);
cursorRect.x += w;
*p = c;
}
RenderText(screen, font, markedText, markedRect.x, markedRect.y, textColor);
TTF_SizeUTF8(font, markedText, &w, &h);
#endif
......@@ -192,8 +247,6 @@ void Redraw()
underlineRect.h = 2;
underlineRect.w = w;
cursorRect.x += w + 1;
SDL_FillRect(screen, &underlineRect, lineColor);
}
......@@ -295,13 +348,13 @@ int main(int argc, char *argv[])
fprintf(stderr, "Keyboard: text input \"%s\"\n", event.text.text);
if (SDL_strlen(text) + SDL_strlen(event.text.text) < sizeof(text))
SDL_strlcpy(text + SDL_strlen(text), event.text.text, sizeof(text));
SDL_strlcat(text, event.text.text, sizeof(text));
fprintf(stderr, "text inputed: %s\n", text);
// After text inputed, we can clear up markedText because it
// is committed
markedText = NULL;
markedText[0] = 0;
Redraw();
break;
......@@ -309,7 +362,8 @@ int main(int argc, char *argv[])
fprintf(stderr, "text editing \"%s\", selected range (%d, %d)\n",
event.edit.text, event.edit.start, event.edit.length);
markedText = event.edit.text;
strcpy(markedText, event.edit.text);
cursor = event.edit.start;
Redraw();
break;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment