mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-06 09:29:38 +01:00
JBR-4687: Japanese IME input window hides what is being typed.
Uses CFS_EXCLUDE instead of CFS_CANDIDATEPOS in the ::ImmSetCandidateWindow() native API, which is more powerful and allows to take into account the issue's case. (cherry picked from commit0afe6c37bb) (cherry picked from commitfa3d03b373)
This commit is contained in:
committed by
jbrbot
parent
12fa92f956
commit
85ef4dd792
@@ -593,27 +593,35 @@ final class WInputMethod extends InputMethodAdapter
|
||||
Runnable r = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
Component client = getClientComponent();
|
||||
Rectangle caretRect = null;
|
||||
|
||||
if (client != null) {
|
||||
if (!client.isShowing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (haveActiveClient()) {
|
||||
Rectangle rc = inputContext.getTextLocation(TextHitInfo.leading(0));
|
||||
x = rc.x;
|
||||
y = rc.y + rc.height;
|
||||
} else {
|
||||
Point pt = client.getLocationOnScreen();
|
||||
Dimension size = client.getSize();
|
||||
x = pt.x;
|
||||
y = pt.y + size.height;
|
||||
caretRect = inputContext.getTextLocation(TextHitInfo.leading(0));
|
||||
}
|
||||
if (caretRect == null) {
|
||||
Point pt = client.getLocationOnScreen();
|
||||
Dimension size = client.getSize();
|
||||
caretRect = new Rectangle(pt, size);
|
||||
}
|
||||
}
|
||||
|
||||
openCandidateWindow(awtFocussedComponentPeer, x, y);
|
||||
if (caretRect == null) {
|
||||
openCandidateWindow(awtFocussedComponentPeer, 0, 0, 0, 0);
|
||||
} else {
|
||||
openCandidateWindow(
|
||||
awtFocussedComponentPeer,
|
||||
caretRect.x,
|
||||
caretRect.y,
|
||||
caretRect.x + caretRect.width - ( (caretRect.width > 0) ? 1 : 0),
|
||||
caretRect.y + caretRect.height - ( (caretRect.height > 0) ? 1 : 0)
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
WToolkit.postEvent(WToolkit.targetToAppContext(source),
|
||||
@@ -657,6 +665,6 @@ final class WInputMethod extends InputMethodAdapter
|
||||
private native String getNativeIMMDescription();
|
||||
static native Locale getNativeLocale();
|
||||
static native boolean setNativeLocale(String localeName);
|
||||
private native void openCandidateWindow(WComponentPeer peer, int x, int y);
|
||||
private native void openCandidateWindow(WComponentPeer peer, int caretLeftX, int caretTopY, int caretRightX, int caretBottomY);
|
||||
private native boolean isCompositionStringAvailable(int context);
|
||||
}
|
||||
|
||||
@@ -4019,49 +4019,63 @@ void AwtComponent::SetCompositionWindow(RECT& r)
|
||||
ImmReleaseContext(hwnd, hIMC);
|
||||
}
|
||||
|
||||
void AwtComponent::OpenCandidateWindow(int x, int y)
|
||||
{
|
||||
void AwtComponent::OpenCandidateWindow(
|
||||
const int caretLeftX,
|
||||
const int caretTopY,
|
||||
const int caretRightX,
|
||||
const int caretBottomY
|
||||
) {
|
||||
UINT bits = 1;
|
||||
POINT p = {0, 0}; // upper left corner of the client area
|
||||
HWND hWnd = ImmGetHWnd();
|
||||
if (!::IsWindowVisible(hWnd)) {
|
||||
return;
|
||||
}
|
||||
|
||||
HWND hTop = GetTopLevelParentForWindow(hWnd);
|
||||
::ClientToScreen(hTop, &p);
|
||||
int sx = ScaleUpAbsX(x) - p.x;
|
||||
int sy = ScaleUpAbsY(y) - p.y;
|
||||
const int sCaretLeftX = ScaleUpAbsX(caretLeftX) - p.x;
|
||||
const int sCaretTopY = ScaleUpAbsY(caretTopY) - p.y;
|
||||
const int sCaretRightX = ScaleUpAbsX(caretRightX) - p.x;
|
||||
const int sCaretBottomY = ScaleUpAbsY(caretBottomY) - p.y;
|
||||
|
||||
if (!m_bitsCandType) {
|
||||
SetCandidateWindow(m_bitsCandType, sx, sy);
|
||||
SetCandidateWindow(m_bitsCandType, sCaretLeftX, sCaretTopY, sCaretRightX, sCaretBottomY);
|
||||
return;
|
||||
}
|
||||
for (int iCandType=0; iCandType<32; iCandType++, bits<<=1) {
|
||||
if ( m_bitsCandType & bits )
|
||||
SetCandidateWindow(iCandType, sx, sy);
|
||||
SetCandidateWindow(iCandType, sCaretLeftX, sCaretTopY, sCaretRightX, sCaretBottomY);
|
||||
}
|
||||
}
|
||||
|
||||
void AwtComponent::SetCandidateWindow(int iCandType, int x, int y)
|
||||
{
|
||||
void AwtComponent::SetCandidateWindow(
|
||||
const int iCandType,
|
||||
const int caretLeftX,
|
||||
const int caretTopY,
|
||||
const int caretRightX,
|
||||
const int caretBottomY
|
||||
) {
|
||||
HWND hwnd = ImmGetHWnd();
|
||||
HIMC hIMC = ImmGetContext(hwnd);
|
||||
if (hIMC) {
|
||||
CANDIDATEFORM cf;
|
||||
cf.dwStyle = CFS_CANDIDATEPOS;
|
||||
ImmGetCandidateWindow(hIMC, 0, &cf);
|
||||
if (x != cf.ptCurrentPos.x || y != cf.ptCurrentPos.y) {
|
||||
if (caretLeftX != cf.ptCurrentPos.x || caretBottomY != cf.ptCurrentPos.y) {
|
||||
cf.dwIndex = iCandType;
|
||||
cf.dwStyle = CFS_CANDIDATEPOS;
|
||||
cf.ptCurrentPos = {x, y};
|
||||
cf.rcArea = {0, 0, 0, 0};
|
||||
cf.dwStyle = CFS_EXCLUDE;
|
||||
cf.ptCurrentPos = {caretLeftX, caretBottomY};
|
||||
cf.rcArea = {caretLeftX, caretTopY, caretRightX, caretBottomY};
|
||||
|
||||
ImmSetCandidateWindow(hIMC, &cf);
|
||||
}
|
||||
COMPOSITIONFORM cfr;
|
||||
cfr.dwStyle = CFS_POINT;
|
||||
ImmGetCompositionWindow(hIMC, &cfr);
|
||||
if (x != cfr.ptCurrentPos.x || y != cfr.ptCurrentPos.y) {
|
||||
if (caretLeftX != cfr.ptCurrentPos.x || caretBottomY != cfr.ptCurrentPos.y) {
|
||||
cfr.dwStyle = CFS_POINT;
|
||||
cfr.ptCurrentPos = {x, y};
|
||||
cfr.ptCurrentPos = {caretLeftX, caretBottomY};
|
||||
cfr.rcArea = {0, 0, 0, 0};
|
||||
ImmSetCompositionWindow(hIMC, &cfr);
|
||||
}
|
||||
|
||||
@@ -545,8 +545,8 @@ public:
|
||||
virtual MsgRouting WmPaste();
|
||||
|
||||
virtual void SetCompositionWindow(RECT &r);
|
||||
virtual void OpenCandidateWindow(int x, int y);
|
||||
virtual void SetCandidateWindow(int iCandType, int x, int y);
|
||||
virtual void OpenCandidateWindow(int caretLeftX, int caretTopY, int caretRightX, int caretBottomY);
|
||||
virtual void SetCandidateWindow(int iCandType, int caretLeftX, int caretTopY, int caretRightX, int caretBottomY);
|
||||
virtual MsgRouting WmImeSetContext(BOOL fSet, LPARAM *lplParam);
|
||||
virtual MsgRouting WmImeNotify(WPARAM subMsg, LPARAM bitsCandType);
|
||||
virtual MsgRouting WmImeStartComposition();
|
||||
|
||||
@@ -407,7 +407,7 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WInputMethod_setStatusWindowVisible
|
||||
* Signature: (Lsun/awt/windows/WComponentPeer;II)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_awt_windows_WInputMethod_openCandidateWindow
|
||||
(JNIEnv *env, jobject self, jobject peer, jint x, jint y)
|
||||
(JNIEnv *env, jobject self, jobject peer, jint caretLeftX, jint caretTopY, jint caretRightX, jint caretBottomY)
|
||||
{
|
||||
TRY;
|
||||
|
||||
@@ -415,19 +415,26 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WInputMethod_openCandidateWindow
|
||||
JNI_CHECK_PEER_RETURN(peer);
|
||||
|
||||
jobject peerGlobalRef = env->NewGlobalRef(peer);
|
||||
if (peerGlobalRef == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// WARNING! MAKELONG macro treats the given values as unsigned.
|
||||
// This may lead to some bugs in multiscreen configurations, as
|
||||
// coordinates can be negative numbers. So, while handling
|
||||
// WM_AWT_OPENCANDIDATEWINDOW message in AwtToolkit, we should
|
||||
// carefully extract right x and y values using GET_X_LPARAM and
|
||||
// GET_Y_LPARAM, not LOWORD and HIWORD
|
||||
// See CR 4805862, AwtToolkit::WndProc
|
||||
// it'd be better to replace the static_cast with a placement new, but it's broken
|
||||
// in debug builds because the "new" expression is redefined as a macro
|
||||
::RECT* const caretRect = static_cast<::RECT*>( safe_Malloc(sizeof(::RECT)) );
|
||||
// safe_Malloc throws an std::bad_alloc if fails, so we don't need to add a nullptr check here
|
||||
*caretRect = ::RECT{ caretLeftX, caretTopY, caretRightX, caretBottomY };
|
||||
|
||||
// use special message to open candidate window in main thread.
|
||||
AwtToolkit::GetInstance().InvokeInputMethodFunction(WM_AWT_OPENCANDIDATEWINDOW,
|
||||
(WPARAM)peerGlobalRef, MAKELONG(x, y));
|
||||
// global ref is deleted in message handler
|
||||
// use a special message to open a candidate window in main thread.
|
||||
static_assert( sizeof(peerGlobalRef) <= sizeof(WPARAM), "peerGlobalRef may not fit into WPARAM type" );
|
||||
static_assert( sizeof(caretRect) <= sizeof(LPARAM), "caretRect may not fit into LPARAM type" );
|
||||
AwtToolkit::GetInstance().InvokeInputMethodFunction(
|
||||
WM_AWT_OPENCANDIDATEWINDOW,
|
||||
reinterpret_cast<WPARAM>(peerGlobalRef),
|
||||
reinterpret_cast<LPARAM>(caretRect)
|
||||
);
|
||||
|
||||
// peerGlobalRef and caretRect are deleted in the message handler (AwtToolkit::WndProc)
|
||||
|
||||
CATCH_BAD_ALLOC;
|
||||
}
|
||||
|
||||
@@ -1219,16 +1219,33 @@ LRESULT CALLBACK AwtToolkit::WndProc(HWND hWnd, UINT message,
|
||||
return (LRESULT)activateKeyboardLayout((HKL)lParam);
|
||||
}
|
||||
case WM_AWT_OPENCANDIDATEWINDOW: {
|
||||
jobject peerObject = (jobject)wParam;
|
||||
AwtComponent* p = (AwtComponent*)JNI_GET_PDATA(peerObject);
|
||||
jobject peerObject = reinterpret_cast<jobject>(wParam);
|
||||
AwtComponent* p = reinterpret_cast<AwtComponent*>( JNI_GET_PDATA(peerObject) );
|
||||
DASSERT( !IsBadReadPtr(p, sizeof(AwtObject)));
|
||||
// fix for 4805862: use GET_X_LPARAM and GET_Y_LPARAM macros
|
||||
// instead of LOWORD and HIWORD
|
||||
p->OpenCandidateWindow(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
|
||||
env->DeleteGlobalRef(peerObject);
|
||||
|
||||
::RECT* caretRect = reinterpret_cast<::RECT*>(lParam);
|
||||
DASSERT( !IsBadReadPtr(caretRect, sizeof(*caretRect)) );
|
||||
|
||||
if ( (p != nullptr) && (caretRect != nullptr) ) {
|
||||
p->OpenCandidateWindow(caretRect->left, caretRect->top, caretRect->right, caretRect->bottom);
|
||||
}
|
||||
|
||||
// Cleaning up
|
||||
if (caretRect != nullptr) {
|
||||
free(caretRect);
|
||||
caretRect = nullptr;
|
||||
}
|
||||
if (peerObject != nullptr) {
|
||||
env->DeleteGlobalRef(peerObject);
|
||||
peerObject = nullptr;
|
||||
}
|
||||
p = nullptr;
|
||||
|
||||
// Returning to AwtToolkit::InvokeInputMethodFunction
|
||||
AwtToolkit& tk = AwtToolkit::GetInstance();
|
||||
tk.m_inputMethodData = 0;
|
||||
::SetEvent(tk.m_inputMethodWaitEvent);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user