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.

746 lines
21 KiB

  1. #include "private.h"
  2. #include "sapilayr.h"
  3. #include "globals.h"
  4. #include "lbarsink.h"
  5. #include "immxutil.h"
  6. #include "mui.h"
  7. #include "slbarid.h"
  8. #include "nui.h"
  9. //////////////////////////////////////////////////////////////////////////////
  10. //
  11. // CLangBarSink
  12. //
  13. //////////////////////////////////////////////////////////////////////////////
  14. //+---------------------------------------------------------------------------
  15. //
  16. // IUnknown
  17. //
  18. //----------------------------------------------------------------------------
  19. STDAPI CLangBarSink::QueryInterface(REFIID riid, void **ppvObj)
  20. {
  21. *ppvObj = NULL;
  22. if (IsEqualIID(riid, IID_IUnknown) ||
  23. IsEqualIID(riid, IID_ITfLangBarEventSink))
  24. {
  25. *ppvObj = SAFECAST(this, ITfLangBarEventSink *);
  26. }
  27. if (*ppvObj)
  28. {
  29. AddRef();
  30. return S_OK;
  31. }
  32. return E_NOINTERFACE;
  33. }
  34. STDAPI_(ULONG) CLangBarSink::AddRef()
  35. {
  36. return ++m_cRef;
  37. }
  38. STDAPI_(ULONG) CLangBarSink::Release()
  39. {
  40. m_cRef--;
  41. Assert(m_cRef >= 0);
  42. if (m_cRef == 0)
  43. {
  44. delete this;
  45. return 0;
  46. }
  47. return m_cRef;
  48. }
  49. //+---------------------------------------------------------------------------
  50. //
  51. // ctor
  52. //
  53. //----------------------------------------------------------------------------
  54. CLangBarSink::CLangBarSink(CSpTask *pSpTask)
  55. {
  56. Dbg_MemSetThisName(TEXT("CLangBarSink"));
  57. Assert(pSpTask);
  58. m_pSpTask = pSpTask;
  59. m_pSpTask->AddRef();
  60. m_nNumItem = 0;
  61. m_fInitSink = FALSE;
  62. m_fPosted = FALSE;
  63. m_fGrammarBuiltOut = FALSE;
  64. m_hDynRule = NULL;
  65. m_cRef = 1;
  66. }
  67. //+---------------------------------------------------------------------------
  68. //
  69. // dtor
  70. //
  71. //----------------------------------------------------------------------------
  72. CLangBarSink::~CLangBarSink()
  73. {
  74. if (m_cplbm)
  75. {
  76. m_cplbm->UnadviseEventSink(m_dwlbimCookie);
  77. }
  78. _UninitItemList();
  79. SafeRelease(m_pSpTask);
  80. }
  81. //+---------------------------------------------------------------------------
  82. //
  83. // SetFocus
  84. //
  85. //----------------------------------------------------------------------------
  86. HRESULT CLangBarSink::OnSetFocus(DWORD dwThreadId)
  87. {
  88. TraceMsg(TF_LB_SINK, "CLangBarSink::OnSetFocus, dwThreadId=%d",dwThreadId);
  89. if (m_fPosted == TRUE) return S_OK;
  90. HWND hwnd = m_pSpTask->GetTip()->_GetWorkerWnd();
  91. if (hwnd)
  92. {
  93. PostMessage(hwnd, WM_PRIV_LBARSETFOCUS, 0, 0);
  94. m_fPosted = TRUE;
  95. }
  96. return S_OK;
  97. }
  98. HRESULT CLangBarSink::_OnSetFocus()
  99. {
  100. HRESULT hr = S_OK;
  101. CSapiIMX *pime = m_pSpTask->GetTip();
  102. TraceMsg(TF_LB_SINK, "LBSINK: _OnSetFocus is called back");
  103. if ( !pime )
  104. return E_FAIL;
  105. // this _tim check is needed because on Win98 the worker window's
  106. // winproc may get called after the window is destroyed.
  107. // In theory we should be ok since we destory the window which calls
  108. // _OnSetFocus() via private message before we release tim
  109. //
  110. if (pime->_tim &&
  111. pime->IsActiveThread() == S_OK)
  112. {
  113. // do we have to do anything?
  114. hr = _InitItemList();
  115. BOOL fCmdOn;
  116. fCmdOn = pime->GetOnOff( ) && pime->GetDICTATIONSTAT_CommandingOnOff( );
  117. // the dynamic toolbar grammar is available only for Voice command mode.
  118. if ( fCmdOn && pime->_LanguageBarCmdEnabled( ))
  119. {
  120. if (hr==S_OK && !m_fGrammarBuiltOut && pime->_IsDictationActiveForLang(GetPlatformResourceLangID()))
  121. {
  122. // build C/C grammar
  123. hr = _BuildGrammar();
  124. _ActivateGrammar(TRUE);
  125. }
  126. }
  127. }
  128. m_fPosted = FALSE;
  129. return hr;
  130. }
  131. //+---------------------------------------------------------------------------
  132. //
  133. // ThreadTerminate
  134. //
  135. //----------------------------------------------------------------------------
  136. HRESULT CLangBarSink::OnThreadTerminate(DWORD dwThreadId)
  137. {
  138. //
  139. // check if the thread is us, release the dynamic grammar object
  140. // via sptask
  141. //
  142. _UninitItemList();
  143. return S_OK;
  144. }
  145. //+---------------------------------------------------------------------------
  146. //
  147. // OnThreadItemChange
  148. //
  149. //----------------------------------------------------------------------------
  150. HRESULT CLangBarSink::OnThreadItemChange(DWORD dwThreadId)
  151. {
  152. //PerfConsider: This is called many times when assembly changes
  153. // This will be corrected in the future but for now
  154. // we re-initialize unnecessary things again/again.
  155. // check if the thread is us,
  156. // to un-initialize the grammar then rebuild the one
  157. TraceMsg(TF_LB_SINK, "CLangBarSink::OnThreadItemChange, dwThreadId=%d", dwThreadId);
  158. _UninitItemList();
  159. OnSetFocus(dwThreadId);
  160. // call sptask to rebuild grammar here
  161. return S_OK;
  162. }
  163. //+---------------------------------------------------------------------------
  164. //
  165. // Init
  166. //
  167. //----------------------------------------------------------------------------
  168. HRESULT CLangBarSink::Init()
  169. {
  170. TraceMsg(TF_LB_SINK, "CLangBarSink::Init is called");
  171. HRESULT hr = _EnsureLangBarMgrs();
  172. if (!m_fInitSink)
  173. {
  174. // the sink leaks if we call this twice
  175. if (S_OK == hr)
  176. {
  177. hr = m_cplbm->AdviseEventSink(this, NULL, 0, &m_dwlbimCookie);
  178. }
  179. m_fInitSink = TRUE;
  180. }
  181. return hr;
  182. }
  183. //+---------------------------------------------------------------------------
  184. //
  185. // Uninit
  186. //
  187. //----------------------------------------------------------------------------
  188. HRESULT CLangBarSink::Uninit()
  189. {
  190. TraceMsg(TF_LB_SINK, "CLangBarSink::Uninit is called");
  191. if (m_cplbm)
  192. {
  193. m_cplbm->UnadviseEventSink(m_dwlbimCookie);
  194. m_cplbm.Release();
  195. }
  196. return S_OK;
  197. }
  198. //+---------------------------------------------------------------------------
  199. //
  200. // _EnsureLangBarMgrs
  201. //
  202. //----------------------------------------------------------------------------
  203. HRESULT CLangBarSink::_EnsureLangBarMgrs()
  204. {
  205. HRESULT hr = S_OK;
  206. TraceMsg(TF_LB_SINK, "CLangBarSink::_EnsureLangBarMgrs is called");
  207. if (!m_cplbm)
  208. {
  209. hr = TF_CreateLangBarMgr(&m_cplbm);
  210. }
  211. if (S_OK == hr && !m_cplbim)
  212. {
  213. DWORD dw;
  214. hr = m_cplbm->GetThreadLangBarItemMgr(GetCurrentThreadId(), &m_cplbim, &dw);
  215. }
  216. return hr;
  217. }
  218. //+---------------------------------------------------------------------------
  219. //
  220. // _AddLBarItem
  221. //
  222. //----------------------------------------------------------------------------
  223. void CLangBarSink::_AddLBarItem(ITfLangBarItem *plbItem)
  224. {
  225. if (plbItem)
  226. {
  227. int nCnt = m_rgItem.Count();
  228. if (m_rgItem.Insert(nCnt, 1))
  229. {
  230. plbItem->AddRef();
  231. m_rgItem.Set(nCnt, plbItem);
  232. m_nNumItem++;
  233. }
  234. }
  235. }
  236. //+---------------------------------------------------------------------------
  237. //
  238. // _InitItemList
  239. //
  240. //----------------------------------------------------------------------------
  241. HRESULT CLangBarSink::_InitItemList()
  242. {
  243. TraceMsg(TF_LB_SINK, "CLangBarSink::_InitItemList is called");
  244. if (0 != m_nNumItem)
  245. {
  246. TraceMsg(TF_LB_SINK, "m_nNumItem=%d, Don't continue InitItemList",m_nNumItem);
  247. return S_OK;
  248. }
  249. HRESULT hr = E_FAIL;
  250. CComPtr<IEnumTfLangBarItems> cpEnum;
  251. Assert(m_cplbim);
  252. if (SUCCEEDED(hr = m_cplbim->EnumItems(&cpEnum)))
  253. {
  254. ITfLangBarItem * plbi;
  255. while (S_OK == cpEnum->Next(1, &plbi, NULL))
  256. {
  257. hr = S_OK; // OK if there's at least one
  258. DWORD dwStatus;
  259. plbi->GetStatus(&dwStatus);
  260. // add buttons that are not diabled or hidden
  261. if ((dwStatus & (TF_LBI_STATUS_HIDDEN|TF_LBI_STATUS_DISABLED))==0)
  262. {
  263. _AddLBarItem(plbi);
  264. }
  265. plbi->Release();
  266. }
  267. }
  268. return hr;
  269. }
  270. //+---------------------------------------------------------------------------
  271. //
  272. // _UninitItemList
  273. //
  274. //----------------------------------------------------------------------------
  275. void CLangBarSink::_UninitItemList()
  276. {
  277. TraceMsg(TF_LB_SINK, "CLangBarSink::_UninitItemList is called");
  278. if (int nCnt = m_rgItem.Count())
  279. {
  280. int i = 0;
  281. while (i < nCnt)
  282. {
  283. ITfLangBarItem * plbi = m_rgItem.Get(i);
  284. if (plbi)
  285. plbi->Release();
  286. i++;
  287. }
  288. m_rgItem.Clear();
  289. }
  290. m_nNumItem = 0;
  291. _UnloadGrammar();
  292. }
  293. //+---------------------------------------------------------------------------
  294. //
  295. // _BuildGrammar
  296. //
  297. // synopsis: build a C&C grammar based on text labels of langbar
  298. // items
  299. //
  300. // BuildGrammar( ) works only when the mode is in Voice command mode.
  301. //
  302. // we have make sure only when voice command is ON and dictation command
  303. // is enabled, this function is called.
  304. //----------------------------------------------------------------------------
  305. HRESULT CLangBarSink::_BuildGrammar()
  306. {
  307. HRESULT hr = E_FAIL;
  308. // get sptask and create a grammar
  309. TraceMsg(TF_LB_SINK, "_BuildGrammar is called");
  310. if (m_pSpTask)
  311. {
  312. CComPtr<ISpRecoContext> cpReco;
  313. // get the grammar loaded to the dictation reco context
  314. //
  315. // it will use the Voice command mode recon context.
  316. hr = m_pSpTask->GetRecoContextForCommand(&cpReco);
  317. TraceMsg(TF_LB_SINK, "TBarGrammar: GetRecoContextForCommand, hr=%x", hr);
  318. if (S_OK == hr)
  319. {
  320. // we don't need to re-create grammar object
  321. if (!m_cpSpGrammar)
  322. {
  323. hr = cpReco->CreateGrammar(GRAM_ID_TBCMD, &m_cpSpGrammar);
  324. TraceMsg(TF_LB_SINK, "TBarGrammar: Create TOOLBar Grammar");
  325. }
  326. }
  327. if (S_OK == hr)
  328. {
  329. hr = m_cpSpGrammar->ResetGrammar(GetPlatformResourceLangID());
  330. TraceMsg(TF_LB_SINK, "TBarGrammar: ResetGrammar");
  331. }
  332. if (S_OK == hr)
  333. {
  334. // get the rule handle
  335. m_cpSpGrammar->GetRule(GetToolbarCommandRuleName(), RULE_ID_TBCMD, SPRAF_TopLevel|SPRAF_Active|SPRAF_Dynamic, TRUE, &m_hDynRule);
  336. TraceMsg(TF_LB_SINK, "TBarGrammar:Get Rule Handle");
  337. // then activate the rule
  338. }
  339. if (S_OK == hr)
  340. {
  341. // enumerate all the buttons,
  342. // see if they are either ITfLangBarItemBitmapButton
  343. // or ITfLangBarItemButton, that have OnClick method on them
  344. BSTR bstr;
  345. int nBtns = m_rgItem.Count();
  346. for (int i = 0; i < nBtns; i++)
  347. {
  348. GUID guidItem;
  349. if (_GetButtonText(i, &bstr, &guidItem) && bstr)
  350. {
  351. // item and property
  352. // the item can include optional string (?please etc)
  353. // if (_IsItemEnabledForCommand(guidItem))
  354. if ( !IsEqualGUID(guidItem, GUID_LBI_SAPILAYR_COMMANDING) )
  355. {
  356. SPPROPERTYINFO pi = {0};
  357. pi.pszName = bstr;
  358. m_cpSpGrammar->AddWordTransition(m_hDynRule, NULL, bstr, L" ", SPWT_LEXICAL, (float)1.01, &pi);
  359. TraceMsg(TF_LB_SINK, "TBarGrammar: button %S added to grammar", bstr);
  360. }
  361. SysFreeString(bstr);
  362. }
  363. }
  364. //
  365. // add a bogus string that has significant weight so we out weight
  366. // others
  367. //
  368. SPPROPERTYINFO pi = {0};
  369. const WCHAR c_szBogus[] = L"zhoulotskunosprok";
  370. pi.pszName = c_szBogus;
  371. m_cpSpGrammar->AddWordTransition(m_hDynRule, NULL, c_szBogus, L" ", SPWT_LEXICAL, (float)1000.01, &pi);
  372. TraceMsg(TF_LB_SINK, "TBarGrammar: start commit ...");
  373. m_cpSpGrammar->Commit(0);
  374. TraceMsg(TF_LB_SINK, "TBarGrammar:Done commit ...");
  375. m_fGrammarBuiltOut = TRUE;
  376. }
  377. }
  378. TraceMsg(TF_LB_SINK, "_BuildGrammar is done!!!!");
  379. return hr;
  380. }
  381. //+---------------------------------------------------------------------------
  382. //
  383. // _UnloadGrammar
  384. //
  385. //
  386. //----------------------------------------------------------------------------
  387. HRESULT CLangBarSink::_UnloadGrammar()
  388. {
  389. // clear the rule
  390. HRESULT hr = S_OK;
  391. TraceMsg(TF_LB_SINK, "CLangBarSink::_UnloadGrammar is called");
  392. if (m_cpSpGrammar)
  393. {
  394. hr = _ActivateGrammar(FALSE);
  395. if (S_OK == hr)
  396. {
  397. hr = m_cpSpGrammar->ClearRule(m_hDynRule);
  398. if ( hr == S_OK )
  399. m_fGrammarBuiltOut = FALSE; // Next time, the grammar needs to be rebuilt.
  400. }
  401. }
  402. return hr;
  403. }
  404. //+---------------------------------------------------------------------------
  405. //
  406. // _ActivateGrammar
  407. //
  408. // synopsis:
  409. //
  410. //----------------------------------------------------------------------------
  411. HRESULT CLangBarSink::_ActivateGrammar(BOOL fActive)
  412. {
  413. HRESULT hr = S_OK;
  414. TraceMsg(TF_LB_SINK, "TBarGrammar: ActivateGrammar=%d", fActive);
  415. if (m_cpSpGrammar)
  416. {
  417. m_cpSpGrammar->SetRuleState(GetToolbarCommandRuleName(), NULL, fActive ? SPRS_ACTIVE : SPRS_INACTIVE);
  418. }
  419. TraceMsg(TF_LB_SINK, "TBarGrammar: ActivateGrammar is done");
  420. return hr;
  421. }
  422. //+---------------------------------------------------------------------------
  423. //
  424. // ProcessToolBarCommand
  425. //
  426. // When return value is TRUE, there is corresponding button on the toolbar
  427. // otherwise the return value is FALSE
  428. //----------------------------------------------------------------------------
  429. BOOL CLangBarSink::ProcessToolbarCmd(const WCHAR *szProperty)
  430. {
  431. BOOL fRet=FALSE;
  432. Assert(szProperty);
  433. // go through items in the array and call onclick method
  434. // if there is a match
  435. if (szProperty)
  436. {
  437. int nBtns = m_rgItem.Count();
  438. for (int i = 0; i < nBtns; i++)
  439. {
  440. BSTR bstr;
  441. if (_GetButtonText(i, &bstr, NULL) && bstr)
  442. {
  443. if (0 == wcscmp(szProperty, bstr))
  444. {
  445. HRESULT hr = E_FAIL;
  446. CComPtr<ITfLangBarItemButton> cplbiBtn ;
  447. CComPtr<ITfLangBarItemBitmapButton> cplbiBmpBtn ;
  448. POINT pt = {0, 0};
  449. ITfLangBarItem * plbi = m_rgItem.Get(i);
  450. if (plbi)
  451. {
  452. hr = plbi->QueryInterface(IID_ITfLangBarItemButton, (void **)&cplbiBtn);
  453. #ifndef TOOLBAR_CMD_FOR_MENUS
  454. // this code removes the toolbar command from thoese
  455. // items with menus
  456. TF_LANGBARITEMINFO info;
  457. if (S_OK == hr)
  458. {
  459. hr = plbi->GetInfo(&info);
  460. }
  461. if (info.dwStyle & TF_LBI_STYLE_BTN_MENU)
  462. {
  463. // do not click on buttons with menu items
  464. // since we don't hanle commands for the items
  465. }
  466. else
  467. #endif
  468. if (S_OK == hr)
  469. {
  470. // is it OK to call OnClick without specifying rect?
  471. hr = cplbiBtn->OnClick(TF_LBI_CLK_LEFT, pt, NULL);
  472. // OnClick would start a new edit session for some buttons, such
  473. // as "Correction"
  474. //
  475. // The return value could be TS_S_ASYNC or S_OK depends on how
  476. // the application grants the edit request.
  477. //
  478. // We need to check if the hr value is successful.
  479. // not only S_OK.
  480. if ( SUCCEEDED(hr) )
  481. fRet = TRUE;
  482. }
  483. #ifdef TOOLBAR_CMD_FOR_MENUS
  484. TF_LANGBARITEMINFO info;
  485. RECT rc = {0};
  486. if (S_OK == hr)
  487. {
  488. hr = plbi->GetInfo(&info);
  489. }
  490. if (S_OK == hr)
  491. {
  492. hr = m_cplbim->GetItemFloatingRect(0, info.guidItem, &rc);
  493. }
  494. if (S_OK == hr)
  495. {
  496. HWND hwnd = FindWindow(NULL, TF_FLOATINGLANGBAR_WNDTITLEA);
  497. if (hwnd)
  498. {
  499. DWORD dw;
  500. POINT poi;
  501. poi.x = (rc.right + rc.left)/2,
  502. poi.y = (rc.top + rc.bottom)/2,
  503. ::ScreenToClient(hwnd, &poi);
  504. dw = MAKELONG(LOWORD(poi.x), LOWORD(poi.y));
  505. PostMessage(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, dw);
  506. PostMessage(hwnd, WM_LBUTTONUP, 0, dw);
  507. }
  508. }
  509. #endif
  510. }
  511. if (!cplbiBtn)
  512. {
  513. hr = plbi->QueryInterface(IID_ITfLangBarItemBitmapButton, (void **)&cplbiBmpBtn);
  514. if (S_OK == hr)
  515. {
  516. hr = cplbiBtn->OnClick(TF_LBI_CLK_LEFT, pt, NULL);
  517. if ( S_OK == hr )
  518. fRet = TRUE;
  519. }
  520. }
  521. break;
  522. } // if (0 == wcscmpi(szProperty, bstr))
  523. SysFreeString(bstr);
  524. } // if (_GetButtonText(i, bstr))
  525. } // for
  526. }
  527. return fRet;
  528. }
  529. //+---------------------------------------------------------------------------
  530. //
  531. // GetButtonText
  532. //
  533. //----------------------------------------------------------------------------
  534. BOOL CLangBarSink::_GetButtonText(int iBtn, BSTR *pbstr, GUID *pguid)
  535. {
  536. HRESULT hr = E_FAIL;
  537. CComPtr<ITfLangBarItemButton> cplbiBtn ;
  538. CComPtr<ITfLangBarItemBitmapButton> cplbiBmpBtn ;
  539. Assert(iBtn < m_rgItem.Count());
  540. Assert(pbstr);
  541. *pbstr = NULL;
  542. ITfLangBarItem * plbi = m_rgItem.Get(iBtn);
  543. if (plbi)
  544. {
  545. hr = plbi->QueryInterface(IID_ITfLangBarItemButton, (void **)&cplbiBtn);
  546. if (S_OK == hr)
  547. {
  548. hr = cplbiBtn->GetTooltipString(pbstr);
  549. }
  550. }
  551. // only in case when the button does not have a
  552. // regular interface we'd qi for bitmapbutton
  553. if (!cplbiBtn)
  554. {
  555. hr = plbi->QueryInterface(IID_ITfLangBarItemBitmapButton, (void **)&cplbiBmpBtn);
  556. if (S_OK == hr)
  557. {
  558. hr = cplbiBmpBtn->GetTooltipString(pbstr);
  559. }
  560. }
  561. TF_LANGBARITEMINFO Info = {0};
  562. if (S_OK == hr)
  563. {
  564. hr = plbi->GetInfo(&Info);
  565. }
  566. if (S_OK == hr)
  567. {
  568. if (pguid)
  569. {
  570. memcpy(pguid, &(Info.guidItem), sizeof(GUID));
  571. }
  572. if (Info.dwStyle & TF_LBI_STYLE_BTN_MENU)
  573. {
  574. // do not create commands for buttons with menu items
  575. // since we don't hanle commands for the items
  576. hr = S_FALSE;
  577. }
  578. }
  579. if (S_OK != hr && *pbstr)
  580. {
  581. // avoid mem leak
  582. SysFreeString(*pbstr);
  583. }
  584. return S_OK == hr;
  585. }
  586. //+---------------------------------------------------------------------------
  587. //
  588. // OnModalInput
  589. //
  590. //----------------------------------------------------------------------------
  591. STDAPI CLangBarSink::OnModalInput(DWORD dwThreadId, UINT uMsg, WPARAM wParam, LPARAM lParam)
  592. {
  593. return E_NOTIMPL;
  594. }
  595. //+---------------------------------------------------------------------------
  596. //
  597. // ShowFloating
  598. //
  599. //----------------------------------------------------------------------------
  600. STDAPI CLangBarSink::ShowFloating(DWORD dwFlags)
  601. {
  602. return E_NOTIMPL;
  603. }
  604. //+---------------------------------------------------------------------------
  605. //
  606. // GetItemFloatingRect
  607. //
  608. //----------------------------------------------------------------------------
  609. STDAPI CLangBarSink::GetItemFloatingRect(DWORD dwThreadId, REFGUID rguid, RECT *prc)
  610. {
  611. return E_NOTIMPL;
  612. }