270 lines
7.6 KiB
C++
270 lines
7.6 KiB
C++
|
#include "./editboxExtender.h"
|
||
|
#include "./common.h"
|
||
|
|
||
|
#include <commctrl.h>
|
||
|
|
||
|
#define NAEF_USERFLAGSMASK 0x00FFFFFF
|
||
|
#define NAEF_UNICODE 0x01000000
|
||
|
|
||
|
typedef struct __EDITBOXEXTENDER
|
||
|
{
|
||
|
WNDPROC originalProc;
|
||
|
UINT flags;
|
||
|
DWORD dblclkTime;
|
||
|
LPWSTR rollbackText;
|
||
|
} EDITBOXEXTENDER;
|
||
|
|
||
|
#define EDITBOXEXTENDER_PROP L"NullsoftEditboxExtender"
|
||
|
|
||
|
#define GetEditbox(__hwnd) ((EDITBOXEXTENDER*)GetProp((__hwnd), EDITBOXEXTENDER_PROP))
|
||
|
|
||
|
static LRESULT CALLBACK EditboxExtender_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
|
||
|
BOOL EditboxExtender_AttachWindow(HWND hEditbox)
|
||
|
{
|
||
|
if (!IsWindow(hEditbox))
|
||
|
return FALSE;
|
||
|
|
||
|
EDITBOXEXTENDER *editbox = (EDITBOXEXTENDER*)GetProp(hEditbox, EDITBOXEXTENDER_PROP);
|
||
|
if (NULL != editbox) return TRUE;
|
||
|
|
||
|
editbox = (EDITBOXEXTENDER*)calloc(1, sizeof(EDITBOXEXTENDER));
|
||
|
if (NULL == editbox) return FALSE;
|
||
|
|
||
|
if (IsWindowUnicode(hEditbox))
|
||
|
editbox->flags |= NAEF_UNICODE;
|
||
|
|
||
|
editbox->originalProc = (WNDPROC)(LONG_PTR)((0 != (NAEF_UNICODE & editbox->flags)) ?
|
||
|
SetWindowLongPtrW(hEditbox, GWLP_WNDPROC, (LONGX86)(LONG_PTR)EditboxExtender_WindowProc) :
|
||
|
SetWindowLongPtrA(hEditbox, GWLP_WNDPROC, (LONGX86)(LONG_PTR)EditboxExtender_WindowProc));
|
||
|
|
||
|
if (NULL == editbox->originalProc || !SetProp(hEditbox, EDITBOXEXTENDER_PROP, editbox))
|
||
|
{
|
||
|
if (NULL != editbox->originalProc)
|
||
|
{
|
||
|
if (0 != (NAEF_UNICODE & editbox->flags))
|
||
|
SetWindowLongPtrW(hEditbox, GWLP_WNDPROC, (LONGX86)(LONG_PTR)editbox->originalProc);
|
||
|
else
|
||
|
SetWindowLongPtrA(hEditbox, GWLP_WNDPROC, (LONGX86)(LONG_PTR)editbox->originalProc);
|
||
|
}
|
||
|
|
||
|
free(editbox);
|
||
|
return FALSE;
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
static void EditboxExtender_Detach(HWND hwnd)
|
||
|
{
|
||
|
EDITBOXEXTENDER *editbox = GetEditbox(hwnd);
|
||
|
RemoveProp(hwnd, EDITBOXEXTENDER_PROP);
|
||
|
|
||
|
if (NULL == editbox)
|
||
|
return;
|
||
|
|
||
|
if (NULL != editbox->originalProc)
|
||
|
{
|
||
|
if (0 != (NAEF_UNICODE & editbox->flags))
|
||
|
SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)editbox->originalProc);
|
||
|
else
|
||
|
SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)editbox->originalProc);
|
||
|
}
|
||
|
free(editbox);
|
||
|
}
|
||
|
|
||
|
|
||
|
static LRESULT EditboxExtender_CallOrigWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
EDITBOXEXTENDER *editbox = GetEditbox(hwnd);
|
||
|
|
||
|
if (NULL == editbox || NULL == editbox->originalProc)
|
||
|
{
|
||
|
return (0 != (NAEF_UNICODE & editbox->flags)) ?
|
||
|
DefWindowProcW(hwnd, uMsg, wParam, lParam) :
|
||
|
DefWindowProcA(hwnd, uMsg, wParam, lParam);
|
||
|
}
|
||
|
|
||
|
return (0 != (NAEF_UNICODE & editbox->flags)) ?
|
||
|
CallWindowProcW(editbox->originalProc, hwnd, uMsg, wParam, lParam) :
|
||
|
CallWindowProcA(editbox->originalProc, hwnd, uMsg, wParam, lParam);
|
||
|
}
|
||
|
|
||
|
static void EditboxExtender_OnDestroy(HWND hwnd)
|
||
|
{
|
||
|
EDITBOXEXTENDER *editbox = GetEditbox(hwnd);
|
||
|
|
||
|
WNDPROC originalProc = editbox->originalProc;
|
||
|
BOOL fUnicode = (0 != (NAEF_UNICODE & editbox->flags));
|
||
|
|
||
|
EditboxExtender_Detach(hwnd);
|
||
|
|
||
|
if (NULL != originalProc)
|
||
|
{
|
||
|
if (FALSE != fUnicode)
|
||
|
CallWindowProcW(originalProc, hwnd, WM_DESTROY, 0, 0L);
|
||
|
else
|
||
|
CallWindowProcA(originalProc, hwnd, WM_DESTROY, 0, 0L);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static LRESULT EditboxExtender_OnGetDlgCode(HWND hwnd, INT vKey, MSG* pMsg)
|
||
|
{
|
||
|
LRESULT result = EditboxExtender_CallOrigWindowProc(hwnd, WM_GETDLGCODE, (WPARAM)vKey, (LPARAM)pMsg);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
static void EditboxExtender_OnLButtonDown(HWND hwnd, UINT vKey, POINTS pts)
|
||
|
{
|
||
|
EDITBOXEXTENDER *editbox = GetEditbox(hwnd);
|
||
|
if (NULL != editbox)
|
||
|
{
|
||
|
DWORD clickTime = GetTickCount();
|
||
|
if (clickTime >= editbox->dblclkTime && clickTime <= (editbox->dblclkTime + GetDoubleClickTime()))
|
||
|
{
|
||
|
SendMessage(hwnd, EM_SETSEL, 0, -1);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
EditboxExtender_CallOrigWindowProc(hwnd, WM_LBUTTONDOWN, (WPARAM)vKey, *((LPARAM*)&pts));
|
||
|
}
|
||
|
|
||
|
static void EditboxExtender_OnLButtonDblClk(HWND hwnd, UINT vKey, POINTS pts)
|
||
|
{
|
||
|
EDITBOXEXTENDER *editbox = GetEditbox(hwnd);
|
||
|
if (NULL == editbox) return;
|
||
|
|
||
|
DWORD clickTime = GetTickCount();
|
||
|
if (clickTime >= editbox->dblclkTime && clickTime <= (editbox->dblclkTime + 2*GetDoubleClickTime()))
|
||
|
{
|
||
|
INT r = (INT)SendMessage(hwnd, EM_CHARFROMPOS, 0, *(LPARAM*)&pts);
|
||
|
r = LOWORD(r);
|
||
|
SendMessage(hwnd, EM_SETSEL, (WPARAM)r, (LPARAM)r);
|
||
|
editbox->dblclkTime = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
editbox->dblclkTime = clickTime;
|
||
|
}
|
||
|
|
||
|
INT f, l;
|
||
|
SendMessage(hwnd, EM_GETSEL, (WPARAM)&f, (LPARAM)&l);
|
||
|
if (f != l) return;
|
||
|
|
||
|
|
||
|
EditboxExtender_CallOrigWindowProc(hwnd, WM_LBUTTONDBLCLK, (WPARAM)vKey, *((LPARAM*)&pts));
|
||
|
|
||
|
}
|
||
|
|
||
|
static void EditboxExtender_OnChar(HWND hwnd, UINT vKey, UINT state)
|
||
|
{
|
||
|
if (0 == (0x8000 & GetAsyncKeyState(VK_CONTROL)) && 0 == (0x8000 & GetAsyncKeyState(VK_MENU)))
|
||
|
{
|
||
|
HWND hParent = GetAncestor(hwnd, GA_PARENT);
|
||
|
if (NULL != hParent)
|
||
|
{
|
||
|
NMCHAR nmh;
|
||
|
nmh.hdr.hwndFrom = hwnd;
|
||
|
nmh.hdr.idFrom = (INT)(INT_PTR)GetWindowLongPtr(hwnd, GWLP_ID);
|
||
|
nmh.hdr.code = NM_CHAR;
|
||
|
nmh.ch = vKey;
|
||
|
nmh.dwItemNext = 0;
|
||
|
nmh.dwItemPrev = 0;
|
||
|
if (FALSE != (BOOL)SendMessage(hParent, WM_NOTIFY, nmh.hdr.idFrom, (LPARAM)&nmh))
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
EditboxExtender_CallOrigWindowProc(hwnd, WM_CHAR, (WPARAM)vKey, (LPARAM)state);
|
||
|
}
|
||
|
|
||
|
static void EditboxExtender_OnKeyDown(HWND hwnd, UINT vKey, UINT state)
|
||
|
{
|
||
|
HWND hParent = GetAncestor(hwnd, GA_PARENT);
|
||
|
if (NULL != hParent)
|
||
|
{
|
||
|
NMKEY nmh;
|
||
|
nmh.hdr.hwndFrom = hwnd;
|
||
|
nmh.hdr.idFrom = (INT)(INT_PTR)GetWindowLongPtr(hwnd, GWLP_ID);
|
||
|
nmh.hdr.code = NM_KEYDOWN;
|
||
|
nmh.nVKey = vKey;
|
||
|
nmh.uFlags = HIWORD(state);
|
||
|
if (FALSE != (BOOL)SendMessage(hParent, WM_NOTIFY, nmh.hdr.idFrom, (LPARAM)&nmh))
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
EditboxExtender_CallOrigWindowProc(hwnd, WM_KEYDOWN, (WPARAM)vKey, (LPARAM)state);
|
||
|
}
|
||
|
|
||
|
static void EditboxExtender_PasteText(HWND hwnd, LPCWSTR pszClipboard)
|
||
|
{
|
||
|
HWND hParent = GetAncestor(hwnd, GA_PARENT);
|
||
|
if (NULL != hParent)
|
||
|
{
|
||
|
EENMPASTE nmh;
|
||
|
nmh.hdr.hwndFrom = hwnd;
|
||
|
nmh.hdr.idFrom = (INT)(INT_PTR)GetWindowLongPtr(hwnd, GWLP_ID);
|
||
|
nmh.hdr.code = EENM_PASTE;
|
||
|
nmh.text = pszClipboard;
|
||
|
if (FALSE != (BOOL)SendMessage(hParent, WM_NOTIFY, nmh.hdr.idFrom, (LPARAM)&nmh))
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
SendMessage(hwnd, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)pszClipboard);
|
||
|
}
|
||
|
|
||
|
static void EditboxExtender_OnPaste(HWND hwnd)
|
||
|
{
|
||
|
IDataObject *pObject;
|
||
|
HRESULT hr = OleGetClipboard(&pObject);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
FORMATETC fmt = {CF_UNICODETEXT, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
|
||
|
STGMEDIUM stgm;
|
||
|
hr = pObject->GetData(&fmt, &stgm);
|
||
|
if(S_OK == hr)
|
||
|
{
|
||
|
LPCWSTR pClipboard = (LPCWSTR)GlobalLock(stgm.hGlobal);
|
||
|
EditboxExtender_PasteText(hwnd, pClipboard);
|
||
|
|
||
|
GlobalUnlock(stgm.hGlobal);
|
||
|
ReleaseStgMedium(&stgm);
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fmt.cfFormat = CF_TEXT;
|
||
|
hr = pObject->GetData(&fmt, &stgm);
|
||
|
if(S_OK == hr)
|
||
|
{
|
||
|
LPCSTR pClipboardAnsi = (LPCSTR)GlobalLock(stgm.hGlobal);
|
||
|
LPWSTR pClipboard;
|
||
|
if (FAILED(LoginBox_MultiByteToWideChar(CP_ACP, 0, pClipboardAnsi, -1, &pClipboard)))
|
||
|
pClipboard = NULL;
|
||
|
|
||
|
EditboxExtender_PasteText(hwnd, pClipboard);
|
||
|
|
||
|
LoginBox_FreeString(pClipboard);
|
||
|
GlobalUnlock(stgm.hGlobal);
|
||
|
ReleaseStgMedium(&stgm);
|
||
|
}
|
||
|
}
|
||
|
pObject->Release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static LRESULT CALLBACK EditboxExtender_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
switch(uMsg)
|
||
|
{
|
||
|
case WM_DESTROY: EditboxExtender_OnDestroy(hwnd); return 0;
|
||
|
case WM_GETDLGCODE: return EditboxExtender_OnGetDlgCode(hwnd, (INT)wParam, (MSG*)lParam);
|
||
|
case WM_LBUTTONDOWN: EditboxExtender_OnLButtonDown(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0;
|
||
|
case WM_LBUTTONDBLCLK: EditboxExtender_OnLButtonDblClk(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0;
|
||
|
case WM_CHAR: EditboxExtender_OnChar(hwnd, (UINT)wParam, (UINT)lParam); return 0;
|
||
|
case WM_KEYDOWN: EditboxExtender_OnKeyDown(hwnd, (UINT)wParam, (UINT)lParam); return 0;
|
||
|
case WM_PASTE: EditboxExtender_OnPaste(hwnd); return 1;
|
||
|
}
|
||
|
|
||
|
return EditboxExtender_CallOrigWindowProc(hwnd, uMsg, wParam, lParam);
|
||
|
}
|