/* ** Command & Conquer Renegade(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ /****************************************************************************** * * FILE * $Archive: /Commando/Code/wwui/IMECandidate.cpp $ * * DESCRIPTION * * PROGRAMMER * $Author: Denzil_l $ * * VERSION INFO * $Revision: 4 $ * $Modtime: 1/12/02 9:43p $ * ******************************************************************************/ #include "IMECandidate.h" #include "WWDebug.h" namespace IME { /****************************************************************************** * * NAME * IMECandidate::IMECandidate * * DESCRIPTION * Default constructor * * INPUTS * NONE * * RESULT * NONE * ******************************************************************************/ IMECandidate::IMECandidate() : mCandidateSize(0), mCandidates(NULL) { Close(); } /****************************************************************************** * * NAME * IMECandidate::~IMECandidate * * DESCRIPTION * Destructor * * INPUTS * NONE * * RESULT * NONE * ******************************************************************************/ IMECandidate::~IMECandidate() { if (mCandidates) { delete[] mCandidates; } } /****************************************************************************** * * NAME * IMECandidate::Open * * DESCRIPTION * * INPUTS * Index - Candidate Index ID * HWND - Window IME is associated with * CodePage - Code page for current input mode. * Unicode - If true, process IME as unicode; if false, process as MBCS * StartFrom1 - If true, candidates should be displayed starting from 1 * * RESULT * NONE * ******************************************************************************/ void IMECandidate::Open(int id, HWND hwnd, UINT codepage, bool unicode, bool startFrom1) { mIndex = id; mHWND = hwnd; mCodePage = codepage; mUseUnicode = unicode; mStartFrom1 = startFrom1; } /****************************************************************************** * * NAME * IMECandidate::Read * * DESCRIPTION * Read the candidate list from IMM * * INPUTS * NONE * * RESULT * NONE * ******************************************************************************/ void IMECandidate::Read(void) { HIMC imc = ImmGetContext(mHWND); if (imc) { DWORD size = 0; // Get the size of the candidate list if (mUseUnicode) { size = ImmGetCandidateListW(imc, mIndex, NULL, 0); } else { size = ImmGetCandidateList(imc, mIndex, NULL, 0); } // Allocate space to hold candidates if ((mCandidates == NULL) || (size > mCandidateSize)) { // Free the existing candidate buffer if (mCandidates != NULL) { delete[] mCandidates; } // Allocate a new buffer to hold the candidates mCandidates = (CANDIDATELIST*)(new unsigned char[size]); mCandidateSize = size; } if (mCandidates != NULL) { if (mUseUnicode) { ImmGetCandidateListW(imc, mIndex, mCandidates, mCandidateSize); } else { ImmGetCandidateList(imc, mIndex, mCandidates, mCandidateSize); } WWDEBUG_SAY(("IMECandidate: Index %d, Style %08lX, Selection %d, PageStart %d, PageSize %d, Count %d\n", mIndex, GetStyle(), GetSelection(), GetPageStart(), GetPageSize(), GetCount())); } ImmReleaseContext(mHWND, imc); } } /****************************************************************************** * * NAME * IMECandidate::Close * * DESCRIPTION * Close the candidate. * * INPUTS * NONE * * RESULT * NONE * ******************************************************************************/ void IMECandidate::Close(void) { mIndex = -1; mHWND = NULL; mCodePage = CP_ACP; mUseUnicode = true; mStartFrom1 = true; if (mCandidates) { memset(mCandidates, 0, sizeof(CANDIDATELIST)); } } /****************************************************************************** * * NAME * IMECandidate::IsValid * * DESCRIPTION * Check if the candidate data is valid. * * INPUTS * NONE * * RESULT * True if valid * ******************************************************************************/ bool IMECandidate::IsValid(void) const { return ((-1 != mIndex) && (mCandidates != NULL)); } /****************************************************************************** * * NAME * IMECandidate::GetIndex * * DESCRIPTION * Get the candidate index ID * * INPUTS * NONE * * RESULT * Candidate index ID * ******************************************************************************/ int IMECandidate::GetIndex(void) const { return mIndex; } /****************************************************************************** * * NAME * IMECandidate::GetStyle * * DESCRIPTION * * INPUTS * NONE * * RESULT * ******************************************************************************/ unsigned long IMECandidate::GetStyle(void) const { WWASSERT(mCandidates != NULL); return mCandidates->dwStyle; } /****************************************************************************** * * NAME * IMECandidate::GetPageStart * * DESCRIPTION * * INPUTS * * RESULT * ******************************************************************************/ unsigned long IMECandidate::GetPageStart(void) const { WWASSERT(mCandidates != NULL); return mCandidates->dwPageStart; } /****************************************************************************** * * NAME * IMECandidate::SetPageStart * * DESCRIPTION * * INPUTS * * RESULT * NONE * ******************************************************************************/ void IMECandidate::SetPageStart(unsigned long start) { WWASSERT((start >=0) && (start < GetCount())); if ((start >=0) && (start < GetCount())) { HIMC imc = ImmGetContext(mHWND); if (imc) { // The IMM documentation says that the candidate list index must // be in the range of 0 - 3 for NI_SETCANDIDATE_PAGESTART WWASSERT((mIndex >= 0 && mIndex <= 3) && "IMM parameter error"); ImmNotifyIME(imc, NI_SETCANDIDATE_PAGESTART, mIndex, start); ImmReleaseContext(mHWND, imc); } } } /****************************************************************************** * * NAME * IMECandidate::GetPageSize * * DESCRIPTION * Get the number of candidates per page. * * INPUTS * NONE * * RESULT * ******************************************************************************/ unsigned long IMECandidate::GetPageSize(void) const { WWASSERT(mCandidates != NULL); return mCandidates->dwPageSize; } /****************************************************************************** * * NAME * IMECandidate::GetCount * * DESCRIPTION * Get the total number of candidates. * * INPUTS * NONE * * RESULT * ******************************************************************************/ // Get the number of candidates in the list. unsigned long IMECandidate::GetCount(void) const { if (mCandidates) { return mCandidates->dwCount; } return 0; } /****************************************************************************** * * NAME * IMECandidate::GetSelection * * DESCRIPTION * Get the index of the currently selected candidate. * * INPUTS * NONE * * RESULT * ******************************************************************************/ unsigned long IMECandidate::GetSelection(void) const { WWASSERT(mCandidates != NULL); return mCandidates->dwSelection; } /****************************************************************************** * * NAME * IMECandidate::IsStartFrom1 * * DESCRIPTION * Check if the candidates should be listed as starting from 1 or 0 * * INPUTS * NONE * * RESULT * ******************************************************************************/ bool IMECandidate::IsStartFrom1(void) const { return mStartFrom1; } /****************************************************************************** * * NAME * IMECandidate::GetCandidate * * DESCRIPTION * Get a candidate string. * * INPUTS * Index of the candidate string to get. * * RESULT * String * ******************************************************************************/ const wchar_t* IMECandidate::GetCandidate(unsigned long index) { if (index < GetCount()) { // For the IME_CAND_CODE style, the candidate list has a special structure // depending on the value of the dwCount member. If dwCount is 1, the dwOffset // member contains a single DBCS character rather than an offset, and no // candidate string is provided. If the dwCount member is greater than 1, // the dwOffset member contains valid offsets, and the candidate strings are // text representations of individual DBCS character values in hexadecimal notation. if ((IME_CAND_CODE == GetStyle()) && (1 == GetCount())) { unsigned long dbcs = mCandidates->dwOffset[0]; // If this char has a lead byte then it is double byte. Swap the bytes // for generate string order if (dbcs & 0xFF00) { dbcs = (((dbcs & 0xFF) << 8) | (dbcs >> 8)); } // Convert char to unicode MultiByteToWideChar(mCodePage, 0, (const char*)&dbcs, -1, mTempString, 1); mTempString[1] = 0; return mTempString; } DWORD offset = mCandidates->dwOffset[index]; const char* candString = ((const char*)mCandidates + offset); if (mUseUnicode) { return ((const wchar_t*)candString); } MultiByteToWideChar(mCodePage, 0, candString, -1, mTempString, (sizeof(mTempString) / sizeof(wchar_t))); mTempString[(sizeof(mTempString) / sizeof(wchar_t)) - 1] = 0; return mTempString; } return NULL; } /****************************************************************************** * * NAME * IMECandidate::SelectCandidate * * DESCRIPTION * Select a string in the candidate list. * * INPUTS * Index of candidate string to select. * * RESULT * NONE * ******************************************************************************/ void IMECandidate::SelectCandidate(unsigned long selection) { HIMC imc = ImmGetContext(mHWND); if (imc) { ImmNotifyIME(imc, NI_SELECTCANDIDATESTR, mIndex, selection); ImmNotifyIME(imc, NI_CLOSECANDIDATE, mIndex, 0); ImmReleaseContext(mHWND, imc); } } /****************************************************************************** * * NAME * IMECandidate::SetView * * DESCRIPTION * * INPUTS * Top - Index of top candidate. * Bottom - Index of bottom candidate. * * RESULT * ******************************************************************************/ void IMECandidate::SetView(unsigned long topIndex, unsigned long bottomIndex) { HIMC imc = ImmGetContext(mHWND); if (imc) { ImmNotifyIME(imc, NI_SETCANDIDATE_PAGESIZE, mIndex, (bottomIndex - topIndex) + 1); ImmNotifyIME(imc, NI_SETCANDIDATE_PAGESTART, mIndex, topIndex); ImmReleaseContext(mHWND, imc); } } } // namespace IME