Пример #1
0
//需要用枚举的办法来获得指定OLE的显示位置,不知道有没有其它更好的办法。
BOOL CImageOle::GetOleRect( LPRECT lpRect )
{
	IRichEditOle *pRichEditOle=NULL;
	LRESULT lRes=m_pRichedit->DuiSendMessage(EM_GETOLEINTERFACE,0,(LPARAM)&pRichEditOle);
	if(!pRichEditOle) return FALSE;

	BOOL bRet=FALSE;

	int nObjCount = pRichEditOle->GetObjectCount();
	int i = 0;
	for (i = 0;i < nObjCount;i++)
	{	
		REOBJECT reo;
		ZeroMemory(&reo, sizeof(REOBJECT));
		reo.cbStruct = sizeof(REOBJECT);

		HRESULT hr = pRichEditOle->GetObject(i, &reo, REO_GETOBJ_POLEOBJ);
		if (hr != S_OK)
			continue;

		reo.poleobj->Release();

		if (reo.poleobj == (IOleObject *)this)
		{

			ITextDocument *pTextDocument = NULL;
			ITextRange *pTextRange = NULL;

			pRichEditOle->QueryInterface(IID_ITextDocument, (void **)&pTextDocument);
			if (!pTextDocument)
				break;

			long nLeft = 0;
			long nBottom = 0;
			pTextDocument->Range(reo.cp, reo.cp, &pTextRange);
			if (reo.dwFlags & REO_BELOWBASELINE)
				hr = pTextRange->GetPoint(TA_BOTTOM|TA_LEFT, &nLeft, &nBottom);
			else
				hr = pTextRange->GetPoint(TA_BASELINE|TA_LEFT, &nLeft, &nBottom);

			pTextDocument->Release();
			pTextRange->Release();

			CRect rcRichedit;
			GetWindowRect(m_pRichedit->GetContainer()->GetHostHwnd(),&rcRichedit);
			CSize szOle=m_pSkin->GetSkinSize();

			lpRect->left   = nLeft - rcRichedit.left;
			lpRect->bottom = nBottom - rcRichedit.top;
			lpRect->right  = lpRect->left + szOle.cx ;
			lpRect->top    = lpRect->bottom - szOle.cy;

			bRet=TRUE;
			break;
		}
	}

	pRichEditOle->Release();
	return bRet;
}
/****************************************************************************
* CRecoEventMgr::SelNotify *
*--------------------------*
*   Description:
*       Called whenever the selection changes.
*       Drops a new listening point onto the list of listening points for
*       this phrase if there is a phrase currently being processed
*       being listened to.
*       Hands back the range to be eventually replaced by recognized
*       text (or deleted).
*   Return:
*       S_OK
*       S_FALSE if nothing had to be done
*       E_OUTOFMEMORY
*       Return value of ITextRange::GetDuplicate()
*       Return value of ITextRange::Collapse()
*****************************************************************************/
HRESULT CRecoEventMgr::SelNotify( ITextRange &rSelRange )
{
    // Only want to queue this listen if we are listening to a phrase
    HRESULT hr = S_FALSE;
    if ( m_fPhraseStarted )
    {
        // Get the time now
        FILETIME ftNow;
        ::CoFileTimeNow( &ftNow );

        // Does this range overlap any of the existing ranges in the list?
        LISTENPOINT *p;
        for ( p = m_pHeadLP; 
            p && AreDisjointRanges( &rSelRange, p->cpRangeToReplace ); 
            p = p->pNext )
            ;

        // If p is not NULL, that means that there is already some listen point
        // that is adjacent to or overlaps this range, so another listen point
        // is not necessary
        if ( !p )
        {
            // Add a new listen point
            LISTENPOINT *pNewPoint = new LISTENPOINT;
            if ( !pNewPoint )
            {
                return E_OUTOFMEMORY;
            }

            // Get the ranges
            rSelRange.GetDuplicate( &(pNewPoint->cpRangeToReplace) );

            // Get the timestamp
            pNewPoint->ftTime = ftNow;

            // This flag will be set by PhraseStart() if appropriate
            pNewPoint->fFromPhraseStart = false;

            // No hypothesis text here yet
            pNewPoint->fHasHypothesisText = false;

            // Put this new listenpoint onto the head of the list
            pNewPoint->pNext = m_pHeadLP;
            m_pHeadLP = pNewPoint;

            long lEndOfRangeToReplace;
            pNewPoint->cpRangeToReplace->GetEnd( &lEndOfRangeToReplace );

            // The selection should be forced to the end of the range to replace;
            // this keeps the selection out of ranges that might be replaced
            // by recognized text
            m_pTextSel->SetRange( 
                    lEndOfRangeToReplace, lEndOfRangeToReplace );

            // If we got here, we were successful
            hr = S_OK;
        }
    }
    return hr;
}   /* CRecoEventMgr::SelNotify */
Пример #3
0
TCHAR *RichEdit::GetText(int start, int end) const
{
	if (end <= start)
		end = GetTextLength();

	if (textDocument != NULL)
	{
		ITextRange *range;
		if (textDocument->Range(start, end, &range) != S_OK) 
			return mir_tstrdup(_T(""));

		BSTR text = NULL;
		if (range->GetText(&text) != S_OK || text == NULL)
		{
			range->Release();
			return mir_tstrdup(_T(""));
		}

		TCHAR *ret = mir_u2t(text);

		SysFreeString(text);

		range->Release();

		return ret;
	}
	else
	{
		int len = GetTextLength();
		TCHAR *tmp = (TCHAR *) mir_alloc(len * sizeof(TCHAR));
		GetWindowText(hwnd, tmp, len);
		tmp[len] = 0;

		TCHAR *ret = (TCHAR *) mir_alloc((end - start + 1) * sizeof(TCHAR));
		memmove(ret, &tmp[start], (end - start) * sizeof(TCHAR));
		ret[end - start] = 0;

		mir_free(tmp);
		return ret;
	}
}
Пример #4
0
static void SetPosition(HWND hwnd)
{
	IRichEditOle* RichEditOle;
	if (SendMessage(hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&RichEditOle) == 0)
		return;

	ITextDocument* TextDocument;
	if (RichEditOle->QueryInterface(IID_ITextDocument, (void**)&TextDocument) != S_OK) {
		RichEditOle->Release();
		return;
	}

	// retrieve text range
	ITextRange* TextRange;
	if (TextDocument->Range(0, 0, &TextRange) != S_OK) {
		TextDocument->Release();
		RichEditOle->Release();
		return;
	}
	TextDocument->Release();

	int objectCount = RichEditOle->GetObjectCount();
	for (int i = objectCount - 1; i >= 0; i--) {
		REOBJECT reObj = {0};
		reObj.cbStruct  = sizeof(REOBJECT);

		HRESULT hr = RichEditOle->GetObject(i, &reObj, REO_GETOBJ_POLEOBJ);
		if (FAILED(hr)) continue;

		ISmileyBase *igsc = NULL;
		if (reObj.clsid == CLSID_NULL) 
			reObj.poleobj->QueryInterface(IID_ISmileyAddSmiley, (void**) &igsc);

		reObj.poleobj->Release();
		if (igsc == NULL) continue;

		TextRange->SetRange(reObj.cp, reObj.cp);

		BOOL res;
		POINT pt;
		RECT rect;
		hr = TextRange->GetPoint(tomStart | TA_BOTTOM | TA_LEFT, &pt.x, &pt.y);
		if (hr == S_OK) {
			res = ScreenToClient(hwnd, &pt);
			rect.bottom = pt.y;
			rect.left = pt.x;
		}
		else rect.bottom = -1;

		hr = TextRange->GetPoint(tomStart | TA_TOP | TA_LEFT, &pt.x, &pt.y);
		if (hr == S_OK) {
			res = ScreenToClient(hwnd, &pt);
			rect.top = pt.y;
			rect.left = pt.x;
		}
		else rect.top = -1;

		igsc->SetPosition(hwnd, &rect);
		igsc->Release();
	}
	TextRange->Release();
	RichEditOle->Release();
}
 static int getIndex(ITextRange range, int charIndex, Array<int> *glyphLengths = NULL) {
     // Count glyphs until pos. There is a bug in glyphRun.GetCharacterSize()
     // and glyphRun.GetContents(), so we cannot count on these.
     // They sometimes contain chars that are in the next run or contain chars
     // from the previous ones....
     // So let's do it the hard way and count only on GetSingleGlyphInRange
     // TODO: cash these results in an int table!
     // IDEA: cash it in the Story of the range, as a lookup table
     // char-index -> glyph-index
     int glyphPos = 0;
     int start = range.GetStart();
     int end = range.GetEnd();
     int size = range.GetSize();
     int scanPos = start;
     while (scanPos < charIndex) {
         // There is a way to discover ligatures: the TextRange's GetSingleGlyphInRange
         // only returns if the length is set to the amount of chars that produce a ligature
         // otherwise it fails. So we can test....
         // TODO: determine maximum ligature size.
         // Assumption is 16 for now.
         // In most cases, 1 will return a result, so there won't be too much iteration here...
         ATEGlyphID id;
         int length = 1;
         int max = MIN(16, size - scanPos);
         for (; length <= max; length++) {
             // First set the text range of the glpyhrun to test GetSingleGlyphInRange on
             range.SetRange(scanPos, scanPos + length);
             // ASCharType type = range.GetCharacterType();
             if (range.GetSingleGlyphInRange(&id)) // Found a full glyph?
                 break;
         }
         // If the length goes all the way to the end, we are likely to have encountered a hyphen glyph, as forced by the
         // AI layout engine's auto hyphenation.
         // There seems to be no way to detect this otherwise, and GetSingleGlyphInRange does not return an id
         // for the situation where the range only describes the one letter before the hyphen. So let's assume
         // this situation is only encountered for hyphens, and adjust glyphLengths, scanPos and glyphPos accordingly
         // further bellow.
         if (length < max || max == 1) {
             scanPos += length;
             // Glyph runs do not count paragraph end chars, so don't count them here either.
             if (range.GetCharacterType() != kParagraphEndChar) {
                 glyphPos++;
                 if (glyphLengths != NULL)
                     glyphLengths->add(length);
             } else if (glyphLengths != NULL) {
                 int last = glyphLengths->size() - 1;
                 if (last >= 0) {
                     int value = glyphLengths->get(last);
                     // Add length to last one. If it's negative, subtract it, since the range starts with paragraph
                     // end chars (see bellow)
                     if (value < 0) value -= length;
                     else value += length;
                     glyphLengths->set(last, value);
                 } else {
                     // Add a negative value, to indicate that range starts with paragraph end chars
                     glyphLengths->add(-length);
                 }
             }
         } else {
             // Increase glyph pos both for the actual char and the hyphen. This is guessing. There might be situations where
             // this is wrong, e.g. ligatures before hypenation, etc. TODO: Test!
             glyphPos += 2;
             scanPos++;
             if (glyphLengths != NULL) {
                 // Normal glyph (what if it's a ligature?)
                 glyphLengths->add(1);
                 // The hyphen, to be ignored as a glyph
                 glyphLengths->add(0);
             }
         }
     }
     if (scanPos > charIndex)
         glyphPos--;
     range.SetRange(start, end);
     return glyphPos;
 }