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.

435 lines
11 KiB

  1. //
  2. //
  3. // Sapilayr TIP CCorrectionHandler implementation.
  4. //
  5. // Implement correction related dictation commands.
  6. // such as
  7. // Correct That
  8. // Recovert
  9. // Correction
  10. //
  11. // Correct <Phrase>
  12. //
  13. // Move the correction related functions to this separate class
  14. //
  15. //
  16. #include "private.h"
  17. #include "sapilayr.h"
  18. #include "correct.h"
  19. // -------------------------------------------------------
  20. //
  21. // Implementation for CCorrectionHandler
  22. //
  23. // -------------------------------------------------------
  24. CCorrectionHandler::CCorrectionHandler(CSapiIMX *psi)
  25. {
  26. m_psi = psi;
  27. fRestoreIP = FALSE;
  28. }
  29. CCorrectionHandler::~CCorrectionHandler( )
  30. {
  31. };
  32. //
  33. // Save the IP right before the candidate UI is opened.
  34. //
  35. // This IP would be restored if the candidate UI is cancelled.
  36. // Or after the alternate text is injected when correct command requires
  37. // to restore this ip.
  38. //
  39. // Client can call _SetRestoreIPFlag( ) to indicate if it wants to restore
  40. // the IP after a new alternate text is injected.
  41. //
  42. // Currently "Correct <Phrase>" command wants to restore the IP, but other
  43. // commands "Correct That, Correction, Reconvert" don't want to restore IP.
  44. //
  45. // Everytime the candidate UI is closed, this IP needs to be released to avoid
  46. // any possible memory leak.
  47. //
  48. HRESULT CCorrectionHandler::_SaveCorrectOrgIP(TfEditCookie ec, ITfContext *pic)
  49. {
  50. CComPtr<ITfRange> cpSel;
  51. HRESULT hr = GetSelectionSimple(ec, pic, (ITfRange **)&cpSel);
  52. if (SUCCEEDED(hr))
  53. {
  54. m_cpOrgIP.Release( );
  55. hr = cpSel->Clone(&m_cpOrgIP);
  56. }
  57. return hr;
  58. }
  59. void CCorrectionHandler::_ReleaseCorrectOrgIP( )
  60. {
  61. if ( m_cpOrgIP )
  62. {
  63. // clear m_cpOrgIP so that it would not affect consequent candidate behavior
  64. //
  65. m_cpOrgIP.Release( );
  66. }
  67. fRestoreIP = FALSE;
  68. }
  69. //
  70. // edit session callback function for RESTORE_CORRECT_ORGIP.
  71. //
  72. HRESULT CCorrectionHandler::_RestoreCorrectOrgIP(TfEditCookie ec, ITfContext *pic)
  73. {
  74. HRESULT hr = S_OK;
  75. // we just want to restore the original saved IP.
  76. if ( m_cpOrgIP )
  77. {
  78. hr = SetSelectionSimple(ec, pic, m_cpOrgIP);
  79. _ReleaseCorrectOrgIP( );
  80. }
  81. return hr;
  82. }
  83. //
  84. // Start an edit session to restore the original IP
  85. //
  86. //
  87. HRESULT CCorrectionHandler::RestoreCorrectOrgIP(ITfContext *pic )
  88. {
  89. HRESULT hr = E_FAIL;
  90. if ( !m_psi ) return E_FAIL;
  91. if (pic)
  92. {
  93. hr = m_psi->_RequestEditSession(ESCB_RESTORE_CORRECT_ORGIP, TF_ES_READWRITE, NULL, pic);
  94. }
  95. return hr;
  96. }
  97. //
  98. // Handle Correct That, Reconvert commands
  99. //
  100. HRESULT CCorrectionHandler::CorrectThat()
  101. {
  102. HRESULT hr = E_FAIL;
  103. if ( !m_psi ) return E_FAIL;
  104. hr = m_psi->_RequestEditSession(ESCB_RECONV_ONIP, TF_ES_READWRITE);
  105. return hr;
  106. }
  107. //
  108. // Edit session callback function for CorrectThat.
  109. //
  110. HRESULT CCorrectionHandler::_CorrectThat(TfEditCookie ec, ITfContext *pic)
  111. {
  112. HRESULT hr = E_FAIL;
  113. ITfRange *pSel = NULL;
  114. TraceMsg(TF_GENERAL, "_CorrectThat is called");
  115. if ( !m_psi ) return E_FAIL;
  116. if (pic)
  117. {
  118. // remove the green bar
  119. m_psi->_KillFeedbackUI(ec, pic, NULL);
  120. hr = m_psi->_GetCmdThatRange(ec, pic, &pSel);
  121. }
  122. if (SUCCEEDED(hr) && pSel)
  123. {
  124. hr = _ReconvertOnRange(pSel);
  125. }
  126. SafeRelease(pSel);
  127. // moved from _HandleRecognition as this is a command
  128. //
  129. m_psi->SaveLastUsedIPRange( );
  130. m_psi->SaveIPRange(NULL);
  131. return hr;
  132. }
  133. HRESULT CCorrectionHandler::_SetSystemReconvFunc( )
  134. {
  135. HRESULT hr = S_OK;
  136. if (!m_cpsysReconv)
  137. {
  138. CComPtr<ITfFunctionProvider> cpsysFuncPrv;
  139. hr = (m_psi->_tim)->GetFunctionProvider(GUID_SYSTEM_FUNCTIONPROVIDER, &cpsysFuncPrv);
  140. if (hr == S_OK)
  141. hr = cpsysFuncPrv->GetFunction(GUID_NULL, IID_ITfFnReconversion, (IUnknown **)&m_cpsysReconv);
  142. }
  143. return hr;
  144. }
  145. void CCorrectionHandler::_ReleaseSystemReconvFunc( )
  146. {
  147. if (m_cpsysReconv)
  148. m_cpsysReconv.Release( );
  149. }
  150. //
  151. // CCorrectionHandler::_ReconvertOnRange
  152. //
  153. // Try to get the candidate UI for the given pRange if this range contains speech alternates
  154. // data.
  155. //
  156. // pRange could be a selection or an IP.
  157. //
  158. //
  159. HRESULT CCorrectionHandler::_ReconvertOnRange(ITfRange *pRange, BOOL *pfConvertable)
  160. {
  161. HRESULT hr = E_FAIL;
  162. ITfRange *pAttrRange = NULL;
  163. BOOL fConvertable = FALSE;
  164. TraceMsg(TF_GENERAL, "_ReconvertOnRange is called");
  165. if ( !pRange ) return E_INVALIDARG;
  166. hr = pRange->Clone(&pAttrRange);
  167. if (S_OK == hr && pAttrRange)
  168. {
  169. CComPtr<ITfRange> cpRangeReconv;
  170. hr = _SetSystemReconvFunc( );
  171. if ( hr == S_OK )
  172. hr = m_cpsysReconv->QueryRange(pAttrRange, &cpRangeReconv, &fConvertable);
  173. if ( (hr == S_OK) && fConvertable && cpRangeReconv)
  174. {
  175. // The text owner could be any other tips, and other tips may want to
  176. // request a new R/W edit session to open reconvert UI.
  177. // Cicero would return E_LOCKED if other tip wants to request edit session while
  178. // speech tip is under an edit session.
  179. //
  180. // To resolve this problem, speech tip just save the cpRangeReconv post a message
  181. // to the work window and then immediatelly end this edit session.
  182. //
  183. // When the work window receives the private message, the window procedure function
  184. // will do a real reconvert work.
  185. m_cpCorrectRange.Release( );
  186. hr = cpRangeReconv->Clone(&m_cpCorrectRange);
  187. if ( hr == S_OK )
  188. PostMessage(m_psi->_GetWorkerWnd( ), WM_PRIV_DORECONVERT, 0, 0);
  189. }
  190. }
  191. SafeRelease(pAttrRange);
  192. if ( pfConvertable )
  193. *pfConvertable = fConvertable;
  194. return hr;
  195. }
  196. //
  197. // CCorrectionHandler::_DoReconvertOnRange
  198. //
  199. // When WM_.... is handled, this function will be called.
  200. // ReconvertOnRange( ) post the above private message and prepare
  201. // all the necessary range data in the class object.
  202. // This function will do the real reconvertion.
  203. //
  204. HRESULT CCorrectionHandler::_DoReconvertOnRange( )
  205. {
  206. HRESULT hr = E_FAIL;
  207. TraceMsg(TF_GENERAL, "_DoReconvertOnRange is called");
  208. if ( !m_cpCorrectRange ) return hr;
  209. hr = _SetSystemReconvFunc( );
  210. if ( hr == S_OK )
  211. hr = m_cpsysReconv->Reconvert(m_cpCorrectRange);
  212. _ReleaseSystemReconvFunc( );
  213. return hr;
  214. }
  215. //
  216. // Moved here from CSapiIMX
  217. //
  218. HRESULT CCorrectionHandler::SetReplaceSelection(ITfRange *pRange, ULONG cchReplaceStart, ULONG cchReplaceChars, ITfContext *pic)
  219. {
  220. HRESULT hr = E_FAIL;
  221. ESDATA esData;
  222. if ( !m_psi ) return E_FAIL;
  223. memset(&esData, 0, sizeof(ESDATA));
  224. esData.lData1 = (LONG_PTR)cchReplaceStart;
  225. esData.lData2 = (LONG_PTR)cchReplaceChars;
  226. esData.pRange = pRange;
  227. hr = m_psi->_RequestEditSession(ESCB_SETREPSELECTION, TF_ES_READWRITE, &esData, pic);
  228. return hr;
  229. }
  230. //
  231. // _SetReplaceSelection
  232. //
  233. // synoposis: calculate the span of text range based on the specified length of
  234. // the selected alternate string (cchReplacexxx)
  235. // then set a selection basedon it.
  236. //
  237. HRESULT CCorrectionHandler::_SetReplaceSelection
  238. (
  239. TfEditCookie ec,
  240. ITfContext *pic, ITfRange *pRange,
  241. ULONG cchReplaceStart,
  242. ULONG cchReplaceChars
  243. )
  244. {
  245. // adjust pRange here
  246. CComPtr<ITfProperty> cpProp;
  247. CComPtr<ITfRange> cpPropRange;
  248. CComPtr<ITfRange> cpClonedPropRange;
  249. if ( !m_psi ) return E_FAIL;
  250. HRESULT hr = pic->GetProperty(GUID_PROP_SAPIRESULTOBJECT, &cpProp);
  251. if (S_OK == hr)
  252. {
  253. hr = cpProp->FindRange(ec, pRange, &cpPropRange, TF_ANCHOR_START);
  254. }
  255. if (S_OK == hr)
  256. {
  257. hr = cpPropRange->Clone(&cpClonedPropRange);
  258. }
  259. if (S_OK == hr)
  260. {
  261. hr = cpClonedPropRange->Collapse(ec, TF_ANCHOR_START);
  262. }
  263. if (S_OK == hr)
  264. {
  265. long cch;
  266. cpClonedPropRange->ShiftStart(ec, cchReplaceStart, &cch, NULL);
  267. cpClonedPropRange->ShiftEnd(ec, cchReplaceChars, &cch, NULL);
  268. }
  269. SetSelectionSimple(ec, pic, cpClonedPropRange);
  270. if ( m_psi->GetDICTATIONSTAT_DictOnOff())
  271. m_psi->_FeedIPContextToSR(ec, pic, cpClonedPropRange);
  272. // discurd IP
  273. m_psi->SaveIPRange(NULL);
  274. return hr;
  275. }
  276. //+---------------------------------------------------------------------------
  277. //
  278. // CCorrectionHandler::InjectAlternateText
  279. //
  280. //----------------------------------------------------------------------------
  281. HRESULT CCorrectionHandler::InjectAlternateText
  282. (
  283. const WCHAR *pwszResult,
  284. LANGID langid,
  285. ITfContext *pic,
  286. BOOL bHandleLeadingSpace
  287. )
  288. {
  289. HRESULT hr = E_FAIL;
  290. Assert(pwszResult);
  291. Assert(pic);
  292. if ( !m_psi ) return E_FAIL;
  293. ESDATA esData;
  294. memset(&esData, 0, sizeof(ESDATA));
  295. esData.pData = (void *)pwszResult;
  296. esData.uByte = (wcslen(pwszResult)+1) * sizeof(WCHAR);
  297. esData.lData1 = (LONG_PTR)langid;
  298. esData.fBool = bHandleLeadingSpace;
  299. hr = m_psi->_RequestEditSession(ESCB_PROCESS_ALTERNATE_TEXT,TF_ES_READWRITE, &esData, pic);
  300. return hr;
  301. }
  302. HRESULT CCorrectionHandler::_ProcessAlternateText(TfEditCookie ec, WCHAR *pwszText,LANGID langid, ITfContext *pic, BOOL bHandleLeadingSpace)
  303. {
  304. HRESULT hr = S_OK;
  305. if ( !m_psi ) return E_FAIL;
  306. CComPtr<ITfRange> cpRangeText;
  307. // Save the current selection as text range which is used
  308. // later to handle leading spaces.
  309. //
  310. if ( bHandleLeadingSpace )
  311. {
  312. CComPtr<ITfRange> cpSelection;
  313. hr = GetSelectionSimple(ec, pic, &cpSelection);
  314. if ( hr == S_OK && cpSelection )
  315. hr = cpSelection->Clone(&cpRangeText);
  316. }
  317. if ( hr == S_OK )
  318. hr = m_psi->_ProcessTextInternal(ec, pwszText, GUID_ATTR_SAPI_INPUT, langid, pic, TRUE);
  319. if ( hr == S_OK && bHandleLeadingSpace && pwszText && cpRangeText)
  320. {
  321. // If the first element is updated by the alternate phrase
  322. // speech tip needs to check if this new alternate wants to
  323. // consume the leading space or if extra space is required to add
  324. // between this phrase and previous phrase.
  325. //
  326. BOOL bConsumeLeadingSpace = FALSE;
  327. WCHAR wchFirstChar = pwszText[0];
  328. if ( iswcntrl(wchFirstChar) || iswpunct(wchFirstChar) )
  329. bConsumeLeadingSpace = TRUE;
  330. if ( hr == S_OK)
  331. hr = m_psi->_ProcessLeadingSpaces(ec, pic, cpRangeText, bConsumeLeadingSpace, langid, FALSE);
  332. }
  333. if ( fRestoreIP )
  334. _RestoreCorrectOrgIP(ec, pic);
  335. else
  336. _ReleaseCorrectOrgIP( );
  337. return hr;
  338. }