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.

487 lines
13 KiB

  1. //
  2. //
  3. // Sapilayr TIP CCapCmdHandler implementation.
  4. //
  5. //
  6. #include "private.h"
  7. #include "sapilayr.h"
  8. #include "capital.h"
  9. // ----------------------------------------------------------------------------------------------------------
  10. //
  11. // Implementation for CCapCmdHandler
  12. //
  13. // -----------------------------------------------------------------------------------------------------------
  14. CCapCmdHandler::CCapCmdHandler(CSapiIMX *psi)
  15. {
  16. m_psi = psi;
  17. }
  18. CCapCmdHandler::~CCapCmdHandler( )
  19. {
  20. };
  21. /* --------------------------------------------------------
  22. // Function Name: ProcessCapCommands
  23. //
  24. // Description: public functions used by command handler
  25. // to handle any Capital related dictation
  26. // commands.
  27. //
  28. // ----------------------------------------------------------*/
  29. HRESULT CCapCmdHandler::ProcessCapCommands(CAPCOMMAND_ID idCapCmd, WCHAR *pwszTextToCap, ULONG ulLen )
  30. {
  31. HRESULT hr = E_FAIL;
  32. if ( !m_psi )
  33. return E_FAIL;
  34. if ( (idCapCmd > CAPCOMMAND_MinIdWithText ) && (!pwszTextToCap || !ulLen))
  35. return E_INVALIDARG;
  36. WCHAR *pwszText=NULL;
  37. ESDATA esData;
  38. memset(&esData, 0, sizeof(ESDATA));
  39. if ( pwszTextToCap )
  40. {
  41. esData.pData = pwszTextToCap;
  42. esData.uByte = (ulLen + 1) * sizeof(WCHAR);
  43. }
  44. esData.lData1 = (LONG_PTR)idCapCmd;
  45. esData.lData2 = (LONG_PTR)ulLen;
  46. hr = m_psi->_RequestEditSession(ESCB_PROCESS_CAP_COMMANDS, TF_ES_READWRITE, &esData);
  47. return hr;
  48. }
  49. /* --------------------------------------------------------
  50. // Function Name: _ProcessCapCommands
  51. //
  52. // Description: Edit session call back funtion for
  53. // ProcessSelectionWord.
  54. //
  55. // it does real work for selection handling
  56. // ----------------------------------------------------------*/
  57. HRESULT CCapCmdHandler::_ProcessCapCommands(TfEditCookie ec,ITfContext *pic, CAPCOMMAND_ID idCapCmd, WCHAR *pwszTextToCap, ULONG ulLen)
  58. {
  59. HRESULT hr = S_OK;
  60. // Get the Dictation Grammar
  61. TraceMsg(TF_GENERAL, "_ProcessCapCommands() is called");
  62. if ( m_psi == NULL)
  63. return E_FAIL;
  64. CComPtr<ITfRange> cpIP;
  65. cpIP = m_psi->GetSavedIP();
  66. if ( cpIP == NULL )
  67. {
  68. // Get the current IP.
  69. hr = GetSelectionSimple(ec, pic, &cpIP);
  70. }
  71. // Start to a new command.
  72. // Clear all the information saved for the previous command handling.
  73. m_dstrTextToCap.Clear( );
  74. m_cpCapRange = cpIP;
  75. m_idCapCmd = idCapCmd;
  76. switch ( idCapCmd )
  77. {
  78. case CAPCOMMAND_CapThat :
  79. case CAPCOMMAND_AllCapsThat :
  80. case CAPCOMMAND_NoCapsThat :
  81. hr = _HandleCapsThat(ec, pic);
  82. break;
  83. case CAPCOMMAND_CapsOn :
  84. hr = _CapsOnOff(ec, pic, TRUE);
  85. break;
  86. case CAPCOMMAND_CapsOff :
  87. hr = _CapsOnOff(ec, pic, FALSE);
  88. break;
  89. // Below commands require pwszTextToCap contains real text to be capitalized
  90. // injected to the document.
  91. case CAPCOMMAND_CapIt :
  92. case CAPCOMMAND_AllCaps :
  93. case CAPCOMMAND_NoCaps :
  94. m_dstrTextToCap.Append(pwszTextToCap);
  95. m_ulLen = ulLen;
  96. hr = _HandleCapsIt(ec, pic);
  97. break;
  98. case CAPCOMMAND_CapLetter :
  99. hr = _HandleCapsThat(ec, pic, towlower(pwszTextToCap[0]));
  100. break;
  101. default :
  102. break;
  103. }
  104. // update the saved ip so that next time the hypothesis will
  105. // start from this new selection.
  106. m_psi->SaveLastUsedIPRange( );
  107. m_psi->SaveIPRange(NULL);
  108. return hr;
  109. }
  110. /* --------------------------------------------------------------
  111. // Function Name: _SetNewText
  112. //
  113. // Description: Inject the new text to m_cpCapRange in
  114. // the document and update necessary property
  115. // data.
  116. //
  117. // --------------------------------------------------------------*/
  118. HRESULT CCapCmdHandler::_SetNewText(TfEditCookie ec,ITfContext *pic, WCHAR *pwszNewText, BOOL fSapiText)
  119. {
  120. HRESULT hr = S_OK;
  121. BOOL fInsertOk;
  122. CComPtr<ITfRange> cpRange;
  123. if (!pwszNewText)
  124. return E_INVALIDARG;
  125. m_cpCapRange->Clone(&cpRange);
  126. hr = cpRange->AdjustForInsert(ec, wcslen(pwszNewText), &fInsertOk);
  127. if (S_OK == hr && fInsertOk)
  128. {
  129. // start a composition here if we haven't already
  130. m_psi->_CheckStartComposition(ec, cpRange);
  131. // set the text
  132. hr = cpRange->SetText(ec, 0, pwszNewText, -1);
  133. if ( fSapiText )
  134. {
  135. //
  136. // set attribute range
  137. //
  138. CComPtr<ITfRange> cpAttrRange = NULL;
  139. CComPtr<ITfProperty> cpProp = NULL;
  140. if (hr == S_OK)
  141. {
  142. hr = pic->GetProperty(GUID_PROP_SAPI_DISPATTR, &cpProp);
  143. }
  144. if (S_OK == hr)
  145. {
  146. hr = cpRange->Clone(&cpAttrRange);
  147. }
  148. if (S_OK == hr && cpAttrRange)
  149. {
  150. SetGUIDPropertyData(m_psi->_GetLibTLS( ), ec, cpProp, cpAttrRange, GUID_ATTR_SAPI_INPUT);
  151. }
  152. //
  153. // setup langid property
  154. //
  155. //_SetLangID(ec, pic, cpRange, langid);
  156. }
  157. if ( hr == S_OK )
  158. {
  159. cpRange->Collapse(ec, TF_ANCHOR_END);
  160. SetSelectionSimple(ec, pic, cpRange);
  161. }
  162. }
  163. return hr;
  164. }
  165. /* ------------------------------------------------------------------
  166. // Function Name: _CapsText
  167. //
  168. // Description: Generate capitalized text based on current
  169. // Capital command id.
  170. //
  171. // Inside this function, it will allocate memory
  172. // for new generated capitaized text.
  173. // Caller is responsible for release the allocated
  174. // memory
  175. // -------------------------------------------------------------------*/
  176. HRESULT CCapCmdHandler::_CapsText(WCHAR **pwszNewText, WCHAR wchLetter)
  177. {
  178. HRESULT hr = S_OK;
  179. WCHAR *pwszNew, *pwszTextToCap;
  180. ULONG i;
  181. // Generate new text based on the requirement
  182. if ( !pwszNewText )
  183. return E_INVALIDARG;
  184. *pwszNewText = NULL;
  185. pwszTextToCap = (WCHAR *)m_dstrTextToCap;
  186. pwszNew = (WCHAR *)cicMemAlloc((m_ulLen+1)*sizeof(WCHAR));
  187. if ( pwszNew )
  188. {
  189. WCHAR wch;
  190. switch (m_idCapCmd)
  191. {
  192. case CAPCOMMAND_CapThat :
  193. case CAPCOMMAND_CapIt :
  194. case CAPCOMMAND_CapLetter :
  195. {
  196. BOOL fFoundFirstAlpha=FALSE;
  197. for (i=0; i<m_ulLen; i++)
  198. {
  199. wch = pwszTextToCap[i];
  200. if ( iswalpha(wch) && !fFoundFirstAlpha )
  201. {
  202. if ( (wchLetter==0) && (m_idCapCmd != CAPCOMMAND_CapLetter) )
  203. pwszNew[i] = towupper(wch);
  204. else
  205. {
  206. if (wch == wchLetter)
  207. pwszNew[i] = towupper(wch);
  208. else
  209. pwszNew[i] = wch;
  210. }
  211. fFoundFirstAlpha = TRUE;
  212. }
  213. else
  214. {
  215. pwszNew[i] = wch;
  216. //
  217. // We treat apostrophe as a normal character when handling capitalization
  218. //
  219. if ( (towupper(wch) == towlower(wch)) && ( wch != L'\'') && ( wch != 0x2019) )
  220. {
  221. // reach to a non-alpha character.
  222. // now start to find first alphar for next word.
  223. fFoundFirstAlpha = FALSE;
  224. }
  225. }
  226. }
  227. pwszNew[m_ulLen] = L'\0';
  228. }
  229. break;
  230. case CAPCOMMAND_AllCapsThat :
  231. case CAPCOMMAND_AllCaps :
  232. for ( i=0; i<m_ulLen; i++)
  233. {
  234. wch = pwszTextToCap[i];
  235. if ( iswalpha(wch) )
  236. pwszNew[i] = towupper(wch);
  237. else
  238. pwszNew[i] = wch;
  239. }
  240. pwszNew[m_ulLen] = L'\0';
  241. break;
  242. case CAPCOMMAND_NoCapsThat :
  243. case CAPCOMMAND_NoCaps :
  244. for ( i=0; i<m_ulLen; i++)
  245. {
  246. wch = pwszTextToCap[i];
  247. if ( iswalpha(wch) )
  248. pwszNew[i] = towlower(wch);
  249. else
  250. pwszNew[i] = wch;
  251. }
  252. pwszNew[m_ulLen] = L'\0';
  253. break;
  254. }
  255. *pwszNewText = pwszNew;
  256. }
  257. if ( *pwszNewText != NULL )
  258. hr = S_OK;
  259. else
  260. {
  261. if ( pwszNew )
  262. cicMemFree(pwszNew);
  263. hr = E_FAIL;
  264. }
  265. return hr;
  266. }
  267. /* ------------------------------------------------------------------
  268. // Function Name: _GetCapPhrase
  269. //
  270. // Description: Generate the range to capitalize.
  271. // it could be previous dictated phrase,
  272. // or current selection,
  273. // or current word around IP or before IP
  274. // depends on the current text situation.
  275. // -------------------------------------------------------------------*/
  276. HRESULT CCapCmdHandler::_GetCapPhrase(TfEditCookie ec,ITfContext *pic, BOOL *fSapiText)
  277. {
  278. HRESULT hr = S_OK;
  279. CComPtr<ITfRange> cpCapRange;
  280. BOOL bSapiText = FALSE;
  281. if ( !m_psi ) return E_FAIL;
  282. if ( !fSapiText ) return E_INVALIDARG;
  283. hr = m_psi->_GetCmdThatRange(ec, pic, &cpCapRange);
  284. if ( hr == S_OK && cpCapRange )
  285. {
  286. m_cpCapRange = cpCapRange;
  287. // Set bSapiText here.
  288. // If the range is inside a dictated phrase, set bSapiText = TRUE;
  289. CComPtr<ITfProperty> cpProp;
  290. CComPtr<ITfRange> cpSapiPropRange;
  291. long l1=0, l2=0;
  292. hr = pic->GetProperty(GUID_PROP_SAPI_DISPATTR, &cpProp);
  293. if ( hr == S_OK )
  294. hr = cpProp->FindRange(ec, cpCapRange, &cpSapiPropRange, TF_ANCHOR_START);
  295. // Is cpRange inside cpSapiPropRange ?
  296. if ( hr == S_OK )
  297. hr = cpCapRange->CompareStart(ec, cpSapiPropRange, TF_ANCHOR_START, &l1);
  298. if ( hr == S_OK )
  299. hr = cpCapRange->CompareEnd(ec, cpSapiPropRange, TF_ANCHOR_END, &l2);
  300. if ( hr == S_OK && (l1>=0 && l2<=0) )
  301. {
  302. // the Range is inside SAPI input range.
  303. bSapiText = TRUE;
  304. }
  305. // hr could be S_FALSE, if the range is not dictated.
  306. // We still treat S_FALSE as S_OK in the return hr.
  307. if ( SUCCEEDED(hr) )
  308. hr = S_OK;
  309. }
  310. *fSapiText = bSapiText;
  311. return hr;
  312. }
  313. HRESULT CCapCmdHandler::_HandleCapsThat(TfEditCookie ec,ITfContext *pic, WCHAR wchLetter)
  314. {
  315. HRESULT hr = S_OK;
  316. BOOL fSapiText;
  317. // Get the range to capitalize
  318. hr = _GetCapPhrase(ec, pic, &fSapiText);
  319. if ( hr == S_OK )
  320. {
  321. CComPtr<ITfRange> cpRangeCloned;
  322. BOOL fEmpty = TRUE;
  323. hr = m_cpCapRange->IsEmpty(ec, &fEmpty);
  324. if ( hr == S_OK && !fEmpty )
  325. {
  326. hr = m_cpCapRange->Clone(&cpRangeCloned);
  327. // Get the text in the CapRange.
  328. if ( hr == S_OK )
  329. {
  330. ULONG ucch;
  331. while(S_OK == hr && (S_OK == cpRangeCloned->IsEmpty(ec, &fEmpty)) && !fEmpty)
  332. {
  333. WCHAR sz[128];
  334. hr = cpRangeCloned->GetText(ec, TF_TF_MOVESTART, sz, ARRAYSIZE(sz)-1, &ucch);
  335. if (S_OK == hr)
  336. {
  337. sz[ucch] = L'\0';
  338. m_dstrTextToCap.Append(sz);
  339. }
  340. }
  341. m_ulLen = m_dstrTextToCap.Length( );
  342. }
  343. if ( hr==S_OK && m_dstrTextToCap)
  344. {
  345. // Generate new text based on the requirement
  346. WCHAR *pwszNewText;
  347. hr = _CapsText(&pwszNewText, wchLetter);
  348. if ( hr == S_OK )
  349. {
  350. hr = _SetNewText(ec, pic, (WCHAR *)pwszNewText, fSapiText);
  351. cicMemFree(pwszNewText);
  352. }
  353. }
  354. }
  355. }
  356. return hr;
  357. }
  358. HRESULT CCapCmdHandler::_CapsOnOff(TfEditCookie ec,ITfContext *pic, BOOL fOn)
  359. {
  360. HRESULT hr = S_OK;
  361. return hr;
  362. }
  363. HRESULT CCapCmdHandler::_HandleCapsIt(TfEditCookie ec,ITfContext *pic)
  364. {
  365. HRESULT hr = S_OK;
  366. if ( m_dstrTextToCap)
  367. {
  368. // Generate new text based on the requirement
  369. WCHAR *pwszNewText;
  370. hr = _CapsText(&pwszNewText);
  371. if ( hr == S_OK )
  372. {
  373. hr = _SetNewText(ec, pic, (WCHAR *)pwszNewText, TRUE);
  374. cicMemFree(pwszNewText);
  375. }
  376. }
  377. return hr;
  378. }