editboxExtender.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. #include "./editboxExtender.h"
  2. #include "./common.h"
  3. #include <commctrl.h>
  4. #define NAEF_USERFLAGSMASK 0x00FFFFFF
  5. #define NAEF_UNICODE 0x01000000
  6. typedef struct __EDITBOXEXTENDER
  7. {
  8. WNDPROC originalProc;
  9. UINT flags;
  10. DWORD dblclkTime;
  11. LPWSTR rollbackText;
  12. } EDITBOXEXTENDER;
  13. #define EDITBOXEXTENDER_PROP L"NullsoftEditboxExtender"
  14. #define GetEditbox(__hwnd) ((EDITBOXEXTENDER*)GetProp((__hwnd), EDITBOXEXTENDER_PROP))
  15. static LRESULT CALLBACK EditboxExtender_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  16. BOOL EditboxExtender_AttachWindow(HWND hEditbox)
  17. {
  18. if (!IsWindow(hEditbox))
  19. return FALSE;
  20. EDITBOXEXTENDER *editbox = (EDITBOXEXTENDER*)GetProp(hEditbox, EDITBOXEXTENDER_PROP);
  21. if (NULL != editbox) return TRUE;
  22. editbox = (EDITBOXEXTENDER*)calloc(1, sizeof(EDITBOXEXTENDER));
  23. if (NULL == editbox) return FALSE;
  24. if (IsWindowUnicode(hEditbox))
  25. editbox->flags |= NAEF_UNICODE;
  26. editbox->originalProc = (WNDPROC)(LONG_PTR)((0 != (NAEF_UNICODE & editbox->flags)) ?
  27. SetWindowLongPtrW(hEditbox, GWLP_WNDPROC, (LONGX86)(LONG_PTR)EditboxExtender_WindowProc) :
  28. SetWindowLongPtrA(hEditbox, GWLP_WNDPROC, (LONGX86)(LONG_PTR)EditboxExtender_WindowProc));
  29. if (NULL == editbox->originalProc || !SetProp(hEditbox, EDITBOXEXTENDER_PROP, editbox))
  30. {
  31. if (NULL != editbox->originalProc)
  32. {
  33. if (0 != (NAEF_UNICODE & editbox->flags))
  34. SetWindowLongPtrW(hEditbox, GWLP_WNDPROC, (LONGX86)(LONG_PTR)editbox->originalProc);
  35. else
  36. SetWindowLongPtrA(hEditbox, GWLP_WNDPROC, (LONGX86)(LONG_PTR)editbox->originalProc);
  37. }
  38. free(editbox);
  39. return FALSE;
  40. }
  41. return TRUE;
  42. }
  43. static void EditboxExtender_Detach(HWND hwnd)
  44. {
  45. EDITBOXEXTENDER *editbox = GetEditbox(hwnd);
  46. RemoveProp(hwnd, EDITBOXEXTENDER_PROP);
  47. if (NULL == editbox)
  48. return;
  49. if (NULL != editbox->originalProc)
  50. {
  51. if (0 != (NAEF_UNICODE & editbox->flags))
  52. SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)editbox->originalProc);
  53. else
  54. SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)editbox->originalProc);
  55. }
  56. free(editbox);
  57. }
  58. static LRESULT EditboxExtender_CallOrigWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  59. {
  60. EDITBOXEXTENDER *editbox = GetEditbox(hwnd);
  61. if (NULL == editbox || NULL == editbox->originalProc)
  62. {
  63. return (0 != (NAEF_UNICODE & editbox->flags)) ?
  64. DefWindowProcW(hwnd, uMsg, wParam, lParam) :
  65. DefWindowProcA(hwnd, uMsg, wParam, lParam);
  66. }
  67. return (0 != (NAEF_UNICODE & editbox->flags)) ?
  68. CallWindowProcW(editbox->originalProc, hwnd, uMsg, wParam, lParam) :
  69. CallWindowProcA(editbox->originalProc, hwnd, uMsg, wParam, lParam);
  70. }
  71. static void EditboxExtender_OnDestroy(HWND hwnd)
  72. {
  73. EDITBOXEXTENDER *editbox = GetEditbox(hwnd);
  74. WNDPROC originalProc = editbox->originalProc;
  75. BOOL fUnicode = (0 != (NAEF_UNICODE & editbox->flags));
  76. EditboxExtender_Detach(hwnd);
  77. if (NULL != originalProc)
  78. {
  79. if (FALSE != fUnicode)
  80. CallWindowProcW(originalProc, hwnd, WM_DESTROY, 0, 0L);
  81. else
  82. CallWindowProcA(originalProc, hwnd, WM_DESTROY, 0, 0L);
  83. }
  84. }
  85. static LRESULT EditboxExtender_OnGetDlgCode(HWND hwnd, INT vKey, MSG* pMsg)
  86. {
  87. LRESULT result = EditboxExtender_CallOrigWindowProc(hwnd, WM_GETDLGCODE, (WPARAM)vKey, (LPARAM)pMsg);
  88. return result;
  89. }
  90. static void EditboxExtender_OnLButtonDown(HWND hwnd, UINT vKey, POINTS pts)
  91. {
  92. EDITBOXEXTENDER *editbox = GetEditbox(hwnd);
  93. if (NULL != editbox)
  94. {
  95. DWORD clickTime = GetTickCount();
  96. if (clickTime >= editbox->dblclkTime && clickTime <= (editbox->dblclkTime + GetDoubleClickTime()))
  97. {
  98. SendMessage(hwnd, EM_SETSEL, 0, -1);
  99. return;
  100. }
  101. }
  102. EditboxExtender_CallOrigWindowProc(hwnd, WM_LBUTTONDOWN, (WPARAM)vKey, *((LPARAM*)&pts));
  103. }
  104. static void EditboxExtender_OnLButtonDblClk(HWND hwnd, UINT vKey, POINTS pts)
  105. {
  106. EDITBOXEXTENDER *editbox = GetEditbox(hwnd);
  107. if (NULL == editbox) return;
  108. DWORD clickTime = GetTickCount();
  109. if (clickTime >= editbox->dblclkTime && clickTime <= (editbox->dblclkTime + 2*GetDoubleClickTime()))
  110. {
  111. INT r = (INT)SendMessage(hwnd, EM_CHARFROMPOS, 0, *(LPARAM*)&pts);
  112. r = LOWORD(r);
  113. SendMessage(hwnd, EM_SETSEL, (WPARAM)r, (LPARAM)r);
  114. editbox->dblclkTime = 0;
  115. }
  116. else
  117. {
  118. editbox->dblclkTime = clickTime;
  119. }
  120. INT f, l;
  121. SendMessage(hwnd, EM_GETSEL, (WPARAM)&f, (LPARAM)&l);
  122. if (f != l) return;
  123. EditboxExtender_CallOrigWindowProc(hwnd, WM_LBUTTONDBLCLK, (WPARAM)vKey, *((LPARAM*)&pts));
  124. }
  125. static void EditboxExtender_OnChar(HWND hwnd, UINT vKey, UINT state)
  126. {
  127. if (0 == (0x8000 & GetAsyncKeyState(VK_CONTROL)) && 0 == (0x8000 & GetAsyncKeyState(VK_MENU)))
  128. {
  129. HWND hParent = GetAncestor(hwnd, GA_PARENT);
  130. if (NULL != hParent)
  131. {
  132. NMCHAR nmh;
  133. nmh.hdr.hwndFrom = hwnd;
  134. nmh.hdr.idFrom = (INT)(INT_PTR)GetWindowLongPtr(hwnd, GWLP_ID);
  135. nmh.hdr.code = NM_CHAR;
  136. nmh.ch = vKey;
  137. nmh.dwItemNext = 0;
  138. nmh.dwItemPrev = 0;
  139. if (FALSE != (BOOL)SendMessage(hParent, WM_NOTIFY, nmh.hdr.idFrom, (LPARAM)&nmh))
  140. return;
  141. }
  142. }
  143. EditboxExtender_CallOrigWindowProc(hwnd, WM_CHAR, (WPARAM)vKey, (LPARAM)state);
  144. }
  145. static void EditboxExtender_OnKeyDown(HWND hwnd, UINT vKey, UINT state)
  146. {
  147. HWND hParent = GetAncestor(hwnd, GA_PARENT);
  148. if (NULL != hParent)
  149. {
  150. NMKEY nmh;
  151. nmh.hdr.hwndFrom = hwnd;
  152. nmh.hdr.idFrom = (INT)(INT_PTR)GetWindowLongPtr(hwnd, GWLP_ID);
  153. nmh.hdr.code = NM_KEYDOWN;
  154. nmh.nVKey = vKey;
  155. nmh.uFlags = HIWORD(state);
  156. if (FALSE != (BOOL)SendMessage(hParent, WM_NOTIFY, nmh.hdr.idFrom, (LPARAM)&nmh))
  157. return;
  158. }
  159. EditboxExtender_CallOrigWindowProc(hwnd, WM_KEYDOWN, (WPARAM)vKey, (LPARAM)state);
  160. }
  161. static void EditboxExtender_PasteText(HWND hwnd, LPCWSTR pszClipboard)
  162. {
  163. HWND hParent = GetAncestor(hwnd, GA_PARENT);
  164. if (NULL != hParent)
  165. {
  166. EENMPASTE nmh;
  167. nmh.hdr.hwndFrom = hwnd;
  168. nmh.hdr.idFrom = (INT)(INT_PTR)GetWindowLongPtr(hwnd, GWLP_ID);
  169. nmh.hdr.code = EENM_PASTE;
  170. nmh.text = pszClipboard;
  171. if (FALSE != (BOOL)SendMessage(hParent, WM_NOTIFY, nmh.hdr.idFrom, (LPARAM)&nmh))
  172. return;
  173. }
  174. SendMessage(hwnd, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)pszClipboard);
  175. }
  176. static void EditboxExtender_OnPaste(HWND hwnd)
  177. {
  178. IDataObject *pObject;
  179. HRESULT hr = OleGetClipboard(&pObject);
  180. if (SUCCEEDED(hr))
  181. {
  182. FORMATETC fmt = {CF_UNICODETEXT, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  183. STGMEDIUM stgm;
  184. hr = pObject->GetData(&fmt, &stgm);
  185. if(S_OK == hr)
  186. {
  187. LPCWSTR pClipboard = (LPCWSTR)GlobalLock(stgm.hGlobal);
  188. EditboxExtender_PasteText(hwnd, pClipboard);
  189. GlobalUnlock(stgm.hGlobal);
  190. ReleaseStgMedium(&stgm);
  191. }
  192. else
  193. {
  194. fmt.cfFormat = CF_TEXT;
  195. hr = pObject->GetData(&fmt, &stgm);
  196. if(S_OK == hr)
  197. {
  198. LPCSTR pClipboardAnsi = (LPCSTR)GlobalLock(stgm.hGlobal);
  199. LPWSTR pClipboard;
  200. if (FAILED(LoginBox_MultiByteToWideChar(CP_ACP, 0, pClipboardAnsi, -1, &pClipboard)))
  201. pClipboard = NULL;
  202. EditboxExtender_PasteText(hwnd, pClipboard);
  203. LoginBox_FreeString(pClipboard);
  204. GlobalUnlock(stgm.hGlobal);
  205. ReleaseStgMedium(&stgm);
  206. }
  207. }
  208. pObject->Release();
  209. }
  210. }
  211. static LRESULT CALLBACK EditboxExtender_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  212. {
  213. switch(uMsg)
  214. {
  215. case WM_DESTROY: EditboxExtender_OnDestroy(hwnd); return 0;
  216. case WM_GETDLGCODE: return EditboxExtender_OnGetDlgCode(hwnd, (INT)wParam, (MSG*)lParam);
  217. case WM_LBUTTONDOWN: EditboxExtender_OnLButtonDown(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0;
  218. case WM_LBUTTONDBLCLK: EditboxExtender_OnLButtonDblClk(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0;
  219. case WM_CHAR: EditboxExtender_OnChar(hwnd, (UINT)wParam, (UINT)lParam); return 0;
  220. case WM_KEYDOWN: EditboxExtender_OnKeyDown(hwnd, (UINT)wParam, (UINT)lParam); return 0;
  221. case WM_PASTE: EditboxExtender_OnPaste(hwnd); return 1;
  222. }
  223. return EditboxExtender_CallOrigWindowProc(hwnd, uMsg, wParam, lParam);
  224. }