Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

356 lines
10 KiB

  1. //
  2. // keys.cpp
  3. //
  4. // ITfKeyEventSink implementation.
  5. //
  6. #include "globals.h"
  7. #include "mark.h"
  8. #include "editsess.h"
  9. class CKeystrokeEditSession : public CEditSessionBase
  10. {
  11. public:
  12. CKeystrokeEditSession(CMarkTextService *pMark, ITfContext *pContext, WPARAM wParam) : CEditSessionBase(pContext)
  13. {
  14. _pMark = pMark;
  15. _pMark->AddRef();
  16. _wParam = wParam;
  17. }
  18. ~CKeystrokeEditSession()
  19. {
  20. _pMark->Release();
  21. }
  22. // ITfEditSession
  23. STDMETHODIMP DoEditSession(TfEditCookie ec);
  24. private:
  25. CMarkTextService *_pMark;
  26. WPARAM _wParam;
  27. };
  28. //+---------------------------------------------------------------------------
  29. //
  30. // _HandleReturn
  31. //
  32. // Returns S_OK to eat the keystroke, S_FALSE otherwise.
  33. //----------------------------------------------------------------------------
  34. HRESULT CMarkTextService::_HandleReturn(TfEditCookie ec, ITfContext *pContext)
  35. {
  36. // just terminate the composition
  37. _TerminateComposition(ec);
  38. return S_OK;
  39. }
  40. //+---------------------------------------------------------------------------
  41. //
  42. // _HandleArrowKey
  43. //
  44. // Update the selection within a composition.
  45. // Returns S_OK to eat the keystroke, S_FALSE otherwise.
  46. //----------------------------------------------------------------------------
  47. HRESULT CMarkTextService::_HandleArrowKey(TfEditCookie ec, ITfContext *pContext, WPARAM wParam)
  48. {
  49. ITfRange *pRangeComposition;
  50. LONG cch;
  51. BOOL fEqual;
  52. TF_SELECTION tfSelection;
  53. ULONG cFetched;
  54. // get the selection
  55. if (pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &cFetched) != S_OK ||
  56. cFetched != 1)
  57. {
  58. // no selection?
  59. return S_OK; // eat the keystroke
  60. }
  61. // get the composition range
  62. if (_pComposition->GetRange(&pRangeComposition) != S_OK)
  63. goto Exit;
  64. // adjust the selection, we won't do anything fancy
  65. if (wParam == VK_LEFT)
  66. {
  67. if (tfSelection.range->IsEqualStart(ec, pRangeComposition, TF_ANCHOR_START, &fEqual) == S_OK &&
  68. !fEqual)
  69. {
  70. tfSelection.range->ShiftStart(ec, -1, &cch, NULL);
  71. }
  72. tfSelection.range->Collapse(ec, TF_ANCHOR_START);
  73. }
  74. else
  75. {
  76. // VK_RIGHT
  77. if (tfSelection.range->IsEqualEnd(ec, pRangeComposition, TF_ANCHOR_END, &fEqual) == S_OK &&
  78. !fEqual)
  79. {
  80. tfSelection.range->ShiftEnd(ec, +1, &cch, NULL);
  81. }
  82. tfSelection.range->Collapse(ec, TF_ANCHOR_END);
  83. }
  84. pContext->SetSelection(ec, 1, &tfSelection);
  85. pRangeComposition->Release();
  86. Exit:
  87. tfSelection.range->Release();
  88. return S_OK; // eat the keystroke
  89. }
  90. //+---------------------------------------------------------------------------
  91. //
  92. // _HandleKeyDown
  93. //
  94. // If the keystroke happens within a composition, eat the key and return S_OK.
  95. // Otherwise, do nothing and return S_FALSE.
  96. //----------------------------------------------------------------------------
  97. HRESULT CMarkTextService::_HandleKeyDown(TfEditCookie ec, ITfContext *pContext, WPARAM wParam)
  98. {
  99. ITfRange *pRangeComposition;
  100. TF_SELECTION tfSelection;
  101. ULONG cFetched;
  102. HRESULT hr;
  103. WCHAR ch;
  104. BOOL fCovered;
  105. if (wParam < 'A' || wParam > 'Z')
  106. return S_OK; // just eat the key if it's not in a range we know how to handle
  107. hr = S_OK; // return S_FALSE to NOT eat the key
  108. // convert the wParam to a WCHAR
  109. if (GetKeyState(VK_SHIFT) & 0x8000)
  110. {
  111. // shift-key, leave it uppercase
  112. ch = (WCHAR)wParam;
  113. }
  114. else
  115. {
  116. // else make it lowercase
  117. ch = (WCHAR)(wParam | 32);
  118. }
  119. // first, test where a keystroke would go in the document if we did an insert
  120. if (pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &cFetched) != S_OK || cFetched != 1)
  121. return S_FALSE;
  122. // is the insertion point covered by a composition?
  123. if (_pComposition->GetRange(&pRangeComposition) == S_OK)
  124. {
  125. fCovered = IsRangeCovered(ec, tfSelection.range, pRangeComposition);
  126. pRangeComposition->Release();
  127. if (!fCovered)
  128. {
  129. hr = S_FALSE; // don't eat the key, it's outside our composition
  130. goto Exit;
  131. }
  132. }
  133. // insert the text
  134. // we use SetText here instead of InsertTextAtSelection because we've already started a composition
  135. // we don't want to the app to adjust the insertion point inside our composition
  136. if (tfSelection.range->SetText(ec, 0, &ch, 1) != S_OK)
  137. goto Exit;
  138. // update the selection, we'll make it an insertion point just past
  139. // the inserted text.
  140. tfSelection.range->Collapse(ec, TF_ANCHOR_END);
  141. pContext->SetSelection(ec, 1, &tfSelection);
  142. // apply our dislay attribute property to the inserted text
  143. // we need to apply it to the entire composition, since the
  144. // display attribute property is static, not static compact
  145. _SetCompositionDisplayAttributes(ec);
  146. Exit:
  147. tfSelection.range->Release();
  148. return hr;
  149. }
  150. //+---------------------------------------------------------------------------
  151. //
  152. // _InitKeystrokeSink
  153. //
  154. // Advise a keystroke sink.
  155. //----------------------------------------------------------------------------
  156. BOOL CMarkTextService::_InitKeystrokeSink()
  157. {
  158. ITfKeystrokeMgr *pKeystrokeMgr;
  159. HRESULT hr;
  160. if (_pThreadMgr->QueryInterface(IID_ITfKeystrokeMgr, (void **)&pKeystrokeMgr) != S_OK)
  161. return FALSE;
  162. hr = pKeystrokeMgr->AdviseKeyEventSink(_tfClientId, (ITfKeyEventSink *)this, TRUE);
  163. pKeystrokeMgr->Release();
  164. return (hr == S_OK);
  165. }
  166. //+---------------------------------------------------------------------------
  167. //
  168. // _UninitKeystrokeSink
  169. //
  170. // Unadvise a keystroke sink. Assumes we have advised one already.
  171. //----------------------------------------------------------------------------
  172. void CMarkTextService::_UninitKeystrokeSink()
  173. {
  174. ITfKeystrokeMgr *pKeystrokeMgr;
  175. if (_pThreadMgr->QueryInterface(IID_ITfKeystrokeMgr, (void **)&pKeystrokeMgr) != S_OK)
  176. return;
  177. pKeystrokeMgr->UnadviseKeyEventSink(_tfClientId);
  178. pKeystrokeMgr->Release();
  179. }
  180. //+---------------------------------------------------------------------------
  181. //
  182. // OnSetFocus
  183. //
  184. // Called by the system whenever this service gets the keystroke device focus.
  185. //----------------------------------------------------------------------------
  186. STDAPI CMarkTextService::OnSetFocus(BOOL fForeground)
  187. {
  188. return S_OK;
  189. }
  190. //+---------------------------------------------------------------------------
  191. //
  192. // OnTestKeyDown
  193. //
  194. // Called by the system to query if this service wants a potential keystroke.
  195. //----------------------------------------------------------------------------
  196. STDAPI CMarkTextService::OnTestKeyDown(ITfContext *pContext, WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
  197. {
  198. *pfEaten = (_pComposition != NULL);
  199. return S_OK;
  200. }
  201. //+---------------------------------------------------------------------------
  202. //
  203. // OnKeyDown
  204. //
  205. // Called by the system to offer this service a keystroke. If *pfEaten == TRUE
  206. // on exit, the application will not handle the keystroke.
  207. //
  208. // This text service is interested in handling keystrokes to demonstrate the
  209. // use the compositions. Some apps will cancel compositions if they receive
  210. // keystrokes while a compositions is ongoing.
  211. //----------------------------------------------------------------------------
  212. STDAPI CMarkTextService::OnKeyDown(ITfContext *pContext, WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
  213. {
  214. CKeystrokeEditSession *pEditSession;
  215. HRESULT hr;
  216. hr = E_FAIL;
  217. *pfEaten = FALSE;
  218. if (_pComposition != NULL) // only eat keys while composing
  219. {
  220. // we'll insert a char ourselves in place of this keystroke
  221. if ((pEditSession = new CKeystrokeEditSession(this, pContext, wParam)) == NULL)
  222. goto Exit;
  223. // we need a lock to do our work
  224. // nb: this method is one of the few places where it is legal to use
  225. // the TF_ES_SYNC flag
  226. if (pContext->RequestEditSession(_tfClientId, pEditSession, TF_ES_SYNC | TF_ES_READWRITE, &hr) != S_OK)
  227. {
  228. hr = E_FAIL;
  229. }
  230. pEditSession->Release();
  231. }
  232. Exit:
  233. // if we made it all the way to the RequestEditSession, then hr is ultimately the
  234. // return code from CKeystrokeEditSession::DoEditSession. Our DoEditSession method
  235. // return S_OK to signal that the keystroke should be eaten, S_FALSE otherwise.
  236. if (hr == S_OK)
  237. {
  238. *pfEaten = TRUE;
  239. }
  240. return S_OK;
  241. }
  242. //+---------------------------------------------------------------------------
  243. //
  244. // DoEditSession
  245. //
  246. //----------------------------------------------------------------------------
  247. STDAPI CKeystrokeEditSession::DoEditSession(TfEditCookie ec)
  248. {
  249. switch (_wParam)
  250. {
  251. case VK_LEFT:
  252. case VK_RIGHT:
  253. return _pMark->_HandleArrowKey(ec, _pContext, _wParam);
  254. case VK_RETURN:
  255. return _pMark->_HandleReturn(ec, _pContext);
  256. case VK_SPACE:
  257. return S_OK;
  258. }
  259. return _pMark->_HandleKeyDown(ec, _pContext, _wParam);
  260. }
  261. //+---------------------------------------------------------------------------
  262. //
  263. // OnTestKeyUp
  264. //
  265. // Called by the system to query this service wants a potential keystroke.
  266. //----------------------------------------------------------------------------
  267. STDAPI CMarkTextService::OnTestKeyUp(ITfContext *pContext, WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
  268. {
  269. *pfEaten = FALSE;
  270. return S_OK;
  271. }
  272. //+---------------------------------------------------------------------------
  273. //
  274. // OnKeyUp
  275. //
  276. // Called by the system to offer this service a keystroke. If *pfEaten == TRUE
  277. // on exit, the application will not handle the keystroke.
  278. //----------------------------------------------------------------------------
  279. STDAPI CMarkTextService::OnKeyUp(ITfContext *pContext, WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
  280. {
  281. *pfEaten = FALSE;
  282. return S_OK;
  283. }
  284. //+---------------------------------------------------------------------------
  285. //
  286. // OnPreservedKey
  287. //
  288. // Called when a hotkey (registered by us, or by the system) is typed.
  289. //----------------------------------------------------------------------------
  290. STDAPI CMarkTextService::OnPreservedKey(ITfContext *pContext, REFGUID rguid, BOOL *pfEaten)
  291. {
  292. *pfEaten = FALSE;
  293. return S_OK;
  294. }