Skip to content

Commit

Permalink
ingame ime
Browse files Browse the repository at this point in the history
  • Loading branch information
wolf109909 committed Jan 4, 2024
1 parent 07d219f commit 93f7297
Show file tree
Hide file tree
Showing 7 changed files with 335 additions and 3 deletions.
2 changes: 2 additions & 0 deletions NorthstarDLL/NorthstarDLL.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ IF EXIST "$(SolutionDir)..\NorthstarCN_Binaries\Northstar.dll" del "$(SolutionDi
<ClInclude Include="client\audio.h" />
<ClInclude Include="client\fontawesome.h" />
<ClInclude Include="client\igig\igig.h" />
<ClInclude Include="client\igig\ime.h" />
<ClInclude Include="client\localchatwriter.h" />
<ClInclude Include="client\r2client.h" />
<ClInclude Include="client\vguihooks.h" />
Expand Down Expand Up @@ -304,6 +305,7 @@ IF EXIST "$(SolutionDir)..\NorthstarCN_Binaries\Northstar.dll" del "$(SolutionDi
<ClCompile Include="engine\netgraph.cpp" />
<ClCompile Include="engine\r2engine.cpp" />
<ClCompile Include="engine\runframe.cpp" />
<ClCompile Include="igig\ime.cpp" />
<ClCompile Include="logging\crashhandler.cpp" />
<ClCompile Include="logging\logging.cpp" />
<ClCompile Include="logging\loghooks.cpp" />
Expand Down
6 changes: 6 additions & 0 deletions NorthstarDLL/NorthstarDLL.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,9 @@
<ClInclude Include="client\igig\igig.h">
<Filter>Header Files\client\igig</Filter>
</ClInclude>
<ClInclude Include="client\igig\ime.h">
<Filter>Header Files\client\igig</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="client\audio.cpp">
Expand Down Expand Up @@ -683,6 +686,9 @@
<ClCompile Include="client\igig\ultralight.cpp">
<Filter>Source Files\client\igig</Filter>
</ClCompile>
<ClCompile Include="igig\ime.cpp">
<Filter>Source Files\client\igig</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<MASM Include="audio_asm.asm">
Expand Down
14 changes: 13 additions & 1 deletion NorthstarDLL/client/igig/igig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#include "imgui/implot.h"
#include "client/fontawesome.h"
#include "dedicated/dedicated.h"

#include "client/igig/ime.h"
typedef HRESULT(__stdcall* fpPresent)(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags);
typedef LRESULT(CALLBACK* fpWndProc)(HWND, UINT, WPARAM, LPARAM);

Expand All @@ -26,6 +26,11 @@ extern LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam

static LRESULT __stdcall hookedWndProc(const HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{

if (ImeWndProc(hWnd, uMsg, wParam, lParam))
{
return true;
}
if (ImGui_ImplWin32_WndProcHandler(hWnd, uMsg, wParam, lParam))
{
return true;
Expand Down Expand Up @@ -75,6 +80,13 @@ static HRESULT __stdcall hookedPresent(IDXGISwapChain* pSwapChain, UINT SyncInte
ImGui_ImplDX11_Init(igig.pDevice.get(), igig.pContext.get());

io.Fonts->AddFontDefault();
ImFontConfig font_config_chs;
strcpy_s(font_config_chs.Name, "MicrosoftYaHei");
font_config_chs.MergeMode = true;
font_config_chs.PixelSnapH = true;
font_config_chs.OversampleH = 2;
font_config_chs.OversampleV = 1;
io.Fonts->AddFontFromFileTTF("c:\\windows\\fonts\\msyh.ttc", 15.0f, &font_config_chs, io.Fonts->GetGlyphRangesChineseFull());

ImFontConfig icons_config;
strcpy_s(icons_config.Name, "FontAwesome");
Expand Down
2 changes: 2 additions & 0 deletions NorthstarDLL/client/igig/ime.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#pragma once
bool ImeWndProc(const HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
310 changes: 310 additions & 0 deletions NorthstarDLL/igig/ime.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,310 @@
#include "client/igig/igig.h"
#include "imgui/imgui.h"
#include "core/hooks.h"
#include "client/fontawesome.h"
#include "client/igig/ime.h"
#include "core/memalloc.h"
#include "shared/keyvalues.h"

AUTOHOOK_INIT()

#define _QWORD __int64;

typedef void (*MessageFunc_t)(void);
typedef __int64(__fastcall* CInputWin32__InternalKeyTyped_t)(__int64, unsigned __int16);
typedef __int64(__fastcall* VGUI__FindOrAddPanelMessageMap_t)(const char*);
typedef __int64(__fastcall* CUtlVector__MessageMapItem_t__AddToTail_t)(__int64, void*);
typedef __int64(__fastcall* CInputWin32__PostKeyMessage_t)(__int64, KeyValues*);
typedef __int64(__fastcall* Panel__LocalToScreen_t)(__int64, DWORD*, DWORD*);
typedef __int64(__fastcall* Panel__GetSize_t)(__int64, DWORD*, DWORD*);
typedef __int64(__fastcall* TextEntry__CursorToPixelSpace_t)(__int64, DWORD, DWORD*, DWORD*);

bool bShouldDrawCandidateList = false;
__int64 CInputWin32__Instance = 0;

CInputWin32__InternalKeyTyped_t CInputWin32__InternalKeyTyped;
VGUI__FindOrAddPanelMessageMap_t VGUI__FindOrAddPanelMessageMap;
CUtlVector__MessageMapItem_t__AddToTail_t CUtlVector__MessageMapItem_t__AddToTail;
CInputWin32__PostKeyMessage_t CInputWin32__PostKeyMessage;
Panel__LocalToScreen_t Panel__LocalToScreen;
Panel__GetSize_t Panel__GetSize;
TextEntry__CursorToPixelSpace_t TextEntry__CursorToPixelSpace;

std::vector<std::wstring> candidates;
std::wstring composite;
DWORD candiX, candiY;

enum DataType_t
{
DATATYPE_VOID,
DATATYPE_CONSTCHARPTR,
DATATYPE_INT,
DATATYPE_FLOAT,
DATATYPE_PTR,
DATATYPE_BOOL,
DATATYPE_KEYVALUES,
DATATYPE_CONSTWCHARPTR,
DATATYPE_UINT64,
DATATYPE_HANDLE, // It's an int, really
};

struct MessageMapItem_t
{
const char* name;

// VC6 aligns this to 16-bytes. Since some of the code has been compiled with VC6,
// we need to enforce the alignment on later compilers to remain compatible.
char pad1[8] = {0};
MessageFunc_t func;
char pad2[8] = {0};

int numParams;

DataType_t firstParamType;
const char* firstParamName;

DataType_t secondParamType;
const char* secondParamName;

int nameSymbol;
int firstParamSymbol;
int secondParamSymbol;
};

std::string convert_from_wstring(const std::wstring& wstr)
{
int num_chars = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), wstr.length(), NULL, 0, NULL, NULL);
std::string strTo;
if (num_chars > 0)
{
strTo.resize(num_chars);
int real_nums = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), wstr.length(), &strTo[0], num_chars, NULL, NULL);
strTo.resize(real_nums);
}
return strTo;
}

bool ImeWndProc(const HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_IME_COMPOSITION:
{
HIMC hIMC = ImmGetContext(hWnd);
if (!hIMC)
{
spdlog::error("[IME] Cannot get IMC context");
return false;
}
if (lParam & GCS_RESULTSTR)
{
LONG dwSize = ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, NULL, 0);
if (dwSize % 2 != 0)
{
dwSize += 1;
}
dwSize /= 2;

WCHAR* hStr = new WCHAR[dwSize];
LONG realSize = ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, hStr, dwSize * 2);
realSize /= 2;

if (ImGui::GetIO().WantCaptureKeyboard)
{
for (int i = 0; i < realSize; i++)
{
ImGui::GetIO().AddInputCharacterUTF16(hStr[i]);
}
}
else
{
for (int i = 0; i < realSize; i++)
{
CInputWin32__InternalKeyTyped(CInputWin32__Instance, hStr[i]);
}
}

delete[] hStr;
}
if (lParam & GCS_COMPSTR)
{
LONG dwSize = ImmGetCompositionStringW(hIMC, GCS_COMPSTR, NULL, 0);
if (dwSize % 2 != 0)
{
dwSize += 1;
}
dwSize /= 2;

WCHAR* hStr = new WCHAR[dwSize];
LONG realSize = ImmGetCompositionStringW(hIMC, GCS_COMPSTR, hStr, dwSize * 2);
realSize /= 2;

composite = std::wstring(hStr, hStr + realSize);

delete[] hStr;
}
ImmReleaseContext(hWnd, hIMC);
return true;
}
case WM_IME_NOTIFY:
{
switch (wParam)
{
case IMN_OPENCANDIDATE:
case IMN_CHANGECANDIDATE:
{
bShouldDrawCandidateList = true;

HIMC hIMC = ImmGetContext(hWnd);
if (!hIMC)
{
spdlog::error("[IME] Cannot get IMC context");
return false;
}

LPCANDIDATELIST lpCandList = NULL;
DWORD dwIndex = 0;
DWORD dwBufLen = ImmGetCandidateList(hIMC, dwIndex, NULL, 0);
if (dwBufLen)
{
lpCandList = (LPCANDIDATELIST)malloc(dwBufLen);
dwBufLen = ImmGetCandidateList(hIMC, dwIndex, lpCandList, dwBufLen);
}

if (lpCandList)
{
candidates.clear();

DWORD dwSelection = lpCandList->dwSelection;
DWORD dwCount = lpCandList->dwCount;
DWORD dwPageStart = lpCandList->dwPageStart;
DWORD dwPageSize = lpCandList->dwPageSize;
for (int i = dwPageStart; i < dwPageStart + dwPageSize; i++)
{
LPWSTR lpCandiString = (LPWSTR)((uintptr_t)lpCandList + lpCandList->dwOffset[i]);
candidates.push_back(std::wstring(lpCandiString));
}
free(lpCandList);
}

ImmReleaseContext(hWnd, hIMC);

CInputWin32__PostKeyMessage(CInputWin32__Instance, new KeyValues("DoIMEUpdateCandidateWindowPos"));

return true;
}
case IMN_CLOSECANDIDATE:
// Ignored due to overlapping with WM_IME_ENDCOMPOSITION
// when the composite string is partially selected.
return true;
}
return true;
}
case WM_IME_STARTCOMPOSITION:
return true;
case WM_IME_ENDCOMPOSITION:
bShouldDrawCandidateList = false;
candidates.clear();
composite = L"";
return true;
case WM_IME_SETCONTEXT:
lParam &= ~ISC_SHOWUICOMPOSITIONWINDOW;
lParam &= ~ISC_SHOWUIGUIDELINE;
lParam &= ~ISC_SHOWUIALLCANDIDATEWINDOW;
return DefWindowProc(hWnd, uMsg, wParam, lParam);
case WM_IME_CONTROL:
case WM_IME_COMPOSITIONFULL:
case WM_IME_SELECT:
case WM_IME_CHAR:
case WM_IME_REQUEST:
case WM_IME_KEYDOWN:
case WM_IME_KEYUP:
return true;
default:
return false;
}
return false;
}

static void draw_candidates()
{
if (!bShouldDrawCandidateList)
{
return;
}

ImGuiWindowFlags window_flags = 0;
window_flags |= ImGuiWindowFlags_NoDecoration;
window_flags |= ImGuiWindowFlags_AlwaysAutoResize;
window_flags |= ImGuiWindowFlags_NoResize;
window_flags |= ImGuiWindowFlags_NoMove;

if (!ImGui::Begin("ChatBox", NULL, window_flags))
{
ImGui::End();
}

auto current_size = ImGui::GetWindowSize();
auto main_viewport = ImGui::GetMainViewport();
auto viewport_pos = main_viewport->WorkPos;
auto viewport_size = main_viewport->WorkSize;
ImGui::SetWindowPos(ImVec2(viewport_pos.x + candiX, viewport_pos.y + candiY));

ImGui::Text("%s", convert_from_wstring(composite).c_str());
ImGui::Separator();

for (int i = 0; i < candidates.size(); i++)
{
ImGui::Text("%d: %s", i + 1, convert_from_wstring(candidates[i]).c_str());
}
ImGui::End();
}

void DoIMEUpdateCandidateWindowPos(__int64 textEntry)
{
DWORD cursorPos = *(DWORD*)(textEntry + 1128);
DWORD cursorX = 0, cursorY = 0;
TextEntry__CursorToPixelSpace(textEntry, cursorPos, &cursorX, &cursorY);

candiX = 0;
candiY = 0;
Panel__GetSize(textEntry, &candiX, &candiY);
candiX = cursorX;
Panel__LocalToScreen(textEntry, &candiX, &candiY);
}

ON_DLL_LOAD("client.dll", IMETEXTENTRY, (CModule module))
{
AUTOHOOK_DISPATCH_MODULE(client.dll)

VGUI__FindOrAddPanelMessageMap = module.Offset(0x75ACB0).As<VGUI__FindOrAddPanelMessageMap_t>();
CUtlVector__MessageMapItem_t__AddToTail = module.Offset(0x34BBE0).As<CUtlVector__MessageMapItem_t__AddToTail_t>();
Panel__LocalToScreen = module.Offset(0x766840).As<Panel__LocalToScreen_t>();
Panel__GetSize = module.Offset(0x75D680).As<Panel__GetSize_t>();
TextEntry__CursorToPixelSpace = module.Offset(0x783BE0).As<TextEntry__CursorToPixelSpace_t>();

MessageMapItem_t entry;
entry.name = "DoIMEUpdateCandidateWindowPos";
entry.func = (MessageFunc_t)DoIMEUpdateCandidateWindowPos;
entry.numParams = 0;
entry.firstParamName = 0;
entry.secondParamName = 0;
entry.firstParamType = DATATYPE_VOID;
entry.secondParamType = DATATYPE_VOID;
entry.nameSymbol = 0;
entry.firstParamSymbol = 0;
entry.secondParamSymbol = 0;

auto map = VGUI__FindOrAddPanelMessageMap("TextEntry");
CUtlVector__MessageMapItem_t__AddToTail(map, &entry);
}

ON_DLL_LOAD("vgui2.dll", CHATBOX, (CModule module))
{
AUTOHOOK_DISPATCH_MODULE(vgui2.dll)

ImGuiManager::instance().addDrawFunction(draw_candidates);
CInputWin32__Instance = (__int64)(module.m_nAddress + 0x121A10);
CInputWin32__PostKeyMessage = module.Offset(0xEDA0).As<CInputWin32__PostKeyMessage_t>();
CInputWin32__InternalKeyTyped = module.Offset(0xCFD0).As<CInputWin32__InternalKeyTyped_t>();
}
4 changes: 2 additions & 2 deletions NorthstarDLL/ns_version.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#ifndef NORTHSTAR_VERSION
// Turning off clang-format here so it doesn't mess with style as it needs to be this way for regex-ing with CI
// clang-format off
#define NORTHSTAR_VERSION 1,16,3,0
#define NORTHSTAR_FILE_VERSION "v1.16.3\0"
#define NORTHSTAR_VERSION 1,16,4,0
#define NORTHSTAR_FILE_VERSION "v1.16.4\0"
// clang-format on
#endif
Binary file modified include/imgui.lib
Binary file not shown.

0 comments on commit 93f7297

Please sign in to comment.