[Date Prev][Date Next][Thread Prev][Thread Next][Thread Index]

RE: [XaraXtreme-dev] Text tool shortcuts



In message <5056CBC646CB4047BB26120F4377DB71DC7AE5@xxxxxxxxxxxxxxxxxxx 
>
          "Phil Martin" <Phil@xxxxxxxx> wrote:

> Er, so to clarify, I think the text tool should be using Char events to
> add characters into text objects and Keypress events to initiate
> actions.

OK, I have implemented that strategy. Find attached below a patch that 
enables text tool shortcuts, together with an implementation of 
ProcessCharCase that is required to allow Ctrl-W to work.

Martin
Index: tools/texttool.cpp
===================================================================
--- tools/texttool.cpp	(Revision 1492)
+++ tools/texttool.cpp	(Arbeitskopie)
@@ -1035,8 +1035,24 @@
 
 BOOL TextTool::OnKeyPress(KeyPress* pKeyPress)
 {
-	TRACEUSER( "jlh92", _T("TextTool::OnKeyPress\n") );
+	TRACEUSER( "wuerthne", _T("TextTool::OnKeyPress, IsChar=%d IsRelease=%d VirtKey=%d\n"),
+			   pKeyPress->IsChar(), pKeyPress->IsRelease(), pKeyPress->GetVirtKey() );
 
+	// NB - each keypress casues three events:
+	//      (1) a key down event (IsChar() = FALSE, IsRelease() = FALSE) - which may not have the
+	//          correct Unicode char value because it has not been through the IM yet
+	//      (2) a char event (IsChar() = TRUE, IsRelease() = FALSE) - with the correct Unicode
+	//          char but with different values for GetVirtKey (e.g., Ctrl+char is reported as
+	//          a ctrl code)
+	//      (3) a release event (IsChar() = FALSE, IsRelease() = TRUE)
+
+	// Our strategy is to use the key down event for shortcuts, to use the char events for
+	// actual input and to ignore the release events. Care must be taken to swallow enough
+	// events, e.g., though cursor movement is handled using the key down event, the
+	// corresponding char event must be swallowed, too, otherwise the reported Unicode
+	// character ends up being inserted in the text object. Finally, all non-char events
+	// we do not swallow here will be processed by the hotkey system.
+
    	// Filter out all key release events 
    	if (pKeyPress->IsRelease())
 	{
@@ -1050,13 +1066,10 @@
 		return FALSE;
 	}
 
-	if( !pKeyPress->IsChar() )
-		return pKeyPress->GetUnicode() == _T(' ');
-
 	// Deal with keypresses that don't dosen't depend on a focus story
 	if (HandleSpecialStoryAndNonStoryKeys(pKeyPress))
 	{
-		TRACEUSER( "jlh92", _T("SpecialStoryAndNonStoryKeys\n") );
+		TRACEUSER( "wuerthne", _T("SpecialStoryAndNonStoryKeys\n") );
 
 		return TRUE;
 	}
@@ -1081,7 +1094,7 @@
 	// We need a focus story do handle a keypress
 	if (TextStory::GetFocusStory() == NULL) 
 	{
-		TRACEUSER( "jlh92", _T("GetFocusStory\n") );
+		TRACEUSER( "wuerthne", _T("GetFocusStory\n") );
 
 		return HandleSpecialNonStoryKeys(pKeyPress);
 	}
@@ -1120,53 +1133,58 @@
    	// First see if this is a special meaning key
 	if (HandleSpecialStoryKeys(pKeyPress, TextStory::GetFocusStory(), TextStory::GetFocusStory()->GetCaret()))
 	{
-		TRACEUSER( "jlh92", _T("HandleSpecialStoryKeys\n") );
+		TRACEUSER( "wuerthne", _T("HandleSpecialStoryKeys\n") );
 
 		return TRUE;
 	}
-	else
+
+	// finally, only proper text input remaining, so we only want Char events
+	if( !pKeyPress->IsChar() )
 	{
-	 	if ( (!pKeyPress->IsAlternative()) ||				    // Alt not down
-				(pKeyPress->IsAlternative() && pKeyPress->IsExtended()) || // Right alt down
-				(pKeyPress->IsAlternative() && pKeyPress->IsConstrain()) ) // Ctrl & left alt down
-	 	{
-			WCHAR UnicodeValue = pKeyPress->GetUnicode();
-			TRACEUSER("jlh92", _T("UnicodeValue from keypress event = %04x"), UnicodeValue);
-			if (HandleDeadKeys(pKeyPress, &UnicodeValue))
-				return TRUE;
-			else
+		TRACEUSER("wuerthne", _T("not char"));
+		return pKeyPress->GetUnicode() == _T(' ');          // always claim the Space key (tool switch)
+	}
+
+	if ( (!pKeyPress->IsAlternative()) ||				    // Alt not down
+		 (pKeyPress->IsAlternative() && pKeyPress->IsExtended()) || // Right alt down
+		 (pKeyPress->IsAlternative() && pKeyPress->IsConstrain()) ) // Ctrl & left alt down
+	{
+		WCHAR UnicodeValue = pKeyPress->GetUnicode();
+		TRACEUSER("wuerthne", _T("UnicodeValue from keypress event = %04x"), UnicodeValue);
+		if (HandleDeadKeys(pKeyPress, &UnicodeValue))
+			return TRUE;
+		else
+		{
+			if ( (UnicodeValue>=32) && ((UnicodeValue < CAMELOT_UNICODE_BASE) || (UnicodeValue > CAMELOT_UNICODE_LAST)))
 			{
-		 		if ( (UnicodeValue>=32) && ((UnicodeValue < CAMELOT_UNICODE_BASE) || (UnicodeValue > CAMELOT_UNICODE_LAST)))
-		 		{
 #ifndef EXCLUDE_FROM_XARALX
-					if ((UnicodeValue < 256) /*&& !TextManager::IsUnicodeCompleteOS()*/)
-						UnicodeValue = UnicodeManager::MultiByteToUnicode(UnicodeValue);
+				if ((UnicodeValue < 256) /*&& !TextManager::IsUnicodeCompleteOS()*/)
+					UnicodeValue = UnicodeManager::MultiByteToUnicode(UnicodeValue);
 #endif
-
-					// Display a blank cursor (thus hiding the pointer)
-					if (!IsBlankCursorUp)
-					{
-						pcCurrentCursor = pcBlankCursor;
-						CursorStack::GSetTop(pcCurrentCursor, CurrentCursorID);
-						IsBlankCursorUp = TRUE;
-					}
-
-					// Create EditTextOp
-					OpTextFormat* pOp = new OpTextFormat();
-					if (pOp != NULL)
-					{
-						TRACEUSER("jlh92", _T("inserting Unicode char %04x"), UnicodeValue);
-						pOp->DoInsertChar(UnicodeValue, OpTextFormat::INSERT);
-						UpdateAfterTyping = TRUE;
-						return TRUE;
-					} 
+				
+				// Display a blank cursor (thus hiding the pointer)
+				if (!IsBlankCursorUp)
+				{
+					pcCurrentCursor = pcBlankCursor;
+					CursorStack::GSetTop(pcCurrentCursor, CurrentCursorID);
+					IsBlankCursorUp = TRUE;
 				}
-				else
-					TRACEUSER( "jlh92", _T("Rejected\n" ) );
+				
+				// Create EditTextOp
+				OpTextFormat* pOp = new OpTextFormat();
+				if (pOp != NULL)
+				{
+					TRACEUSER("jlh92", _T("inserting Unicode char %04x"), UnicodeValue);
+					pOp->DoInsertChar(UnicodeValue, OpTextFormat::INSERT);
+					UpdateAfterTyping = TRUE;
+					return TRUE;
+				} 
 			}
+			else
+				TRACEUSER( "jlh92", _T("Rejected\n" ) );
 		}
 	}
-
+	TRACEUSER("wuerthne", _T("TextTool::OnKeyPress returns FALSE"));
 	return FALSE;
 }
 
@@ -1188,6 +1206,8 @@
 	if (pKeyPress == NULL)
 		return FALSE;
 
+	if (pKeyPress->IsChar()) return FALSE;      // only use non-char events for hotkeys
+
 	BOOL UsedTheKeypress = FALSE;
 	BOOL Errored = FALSE;
 
@@ -1213,7 +1233,7 @@
 
 	if (Errored)
 		InformError();
-
+	TRACEUSER("wuerthne", _T("HandleSpecialStoryAndNonStoryKeys returns %d"), UsedTheKeypress);
 	return UsedTheKeypress;
 }
 
@@ -1246,7 +1266,7 @@
 			UsedTheKeypress = TRUE;		// Just eat the keypress
 			break;
 	}
-
+	TRACEUSER("wuerthne", _T("HandleSpecialNonStoryKeys returns %d"), UsedTheKeypress);
 	return UsedTheKeypress;
 }
 
@@ -1274,6 +1294,7 @@
 	if ((pKeyPress == NULL) || (pStory == NULL) || (pCaret == NULL))
 		return FALSE;
 
+	BOOL IsNonCharEvent = !pKeyPress->IsChar(); // only use non-char events for hotkeys, but eat char events matching our hotkeys
 	BOOL UsedTheKeypress = FALSE;
 	BOOL Errored = FALSE;
 
@@ -1281,29 +1302,31 @@
 	{
 		case CAMKEY(HOME):
 	 		// Move caret to start of line
+			if (IsNonCharEvent)
 	 		{
 				OpTextCaret* pOp = new OpTextCaret();
 				if (pOp != NULL)
 					pOp->DoMoveCaretHome(pKeyPress->IsAdjust(), pKeyPress->IsConstrain()); 
 				else
 					Errored = TRUE;
-				UsedTheKeypress = TRUE;
 			}
+			UsedTheKeypress = TRUE;
 			break;
 		case CAMKEY(END):
 	 		// Move caret to end of line
+			if (IsNonCharEvent)
 	 		{
 				OpTextCaret* pOp = new OpTextCaret();
 				if (pOp != NULL)
 					pOp->DoMoveCaretEnd(pKeyPress->IsAdjust(), pKeyPress->IsConstrain()); 
 				else
 					Errored = TRUE;
-				UsedTheKeypress = TRUE;
 			}
+			UsedTheKeypress = TRUE;
 			break;
 		case CAMKEY(BACK):
 			// delete character before caret, or selected chars if either exists
-			if (pStory->GetSelectionEnd() || pCaret->FindPrevVTNInStory() != NULL)
+			if (IsNonCharEvent && (pStory->GetSelectionEnd() || pCaret->FindPrevVTNInStory() != NULL))
 	 		{
 				OpTextFormat* pOp = new OpTextFormat();
 				if (pOp != NULL)
@@ -1315,7 +1338,7 @@
 			break;
  		case CAMKEY(DELETE):
 			// delete character before caret, or selected chars if either exists
-			if (pStory->GetSelectionEnd() || pCaret->FindNextVTNInStory() != pStory->FindLastVTN())
+			if (IsNonCharEvent && (pStory->GetSelectionEnd() || pCaret->FindNextVTNInStory() != pStory->FindLastVTN()))
 	 		{
 				OpTextFormat* pOp = new OpTextFormat();
 				if (pOp != NULL)
@@ -1327,7 +1350,9 @@
 			break;
  		case CAMKEY(LEFT):
 			// Move/Select caret left one word/character
+			if (IsNonCharEvent)
 			{
+				TRACEUSER("wuerthne", _T("caret left"));
 				OpTextCaret* pOp = new OpTextCaret();
 				if (pOp != NULL)
 					pOp->DoMoveCaretLeft(pKeyPress->IsAdjust(), pKeyPress->IsConstrain());
@@ -1338,6 +1363,7 @@
 			break;
  		case CAMKEY(RIGHT):
 			// Move/Select caret right one word/character
+			if (IsNonCharEvent)
 			{
 				OpTextCaret* pOp = new OpTextCaret();
 				if (pOp != NULL)
@@ -1349,6 +1375,7 @@
 			break;
  		case CAMKEY(UP):
 			// Move/Select caret up a line
+			if (IsNonCharEvent)
 			{
 				OpTextCaret* pOp = new OpTextCaret();
 				if (pOp != NULL)
@@ -1360,6 +1387,7 @@
 			break;
  		case CAMKEY(DOWN):
 			// Move/Select caret down a line
+			if (IsNonCharEvent)			
 			{
 				OpTextCaret* pOp = new OpTextCaret();
 				if (pOp != NULL)
@@ -1371,13 +1399,18 @@
 			break;
  		case CAMKEY(W):
 			// Swap case
+			TRACEUSER("wuerthne", _T("W pressed"));
 			if (pKeyPress->IsConstrain() && !pKeyPress->IsAdjust() )
 			{
-				if (TextStory::GetFocusStory()->GetCaret()->FindNextTextCharInStory() != NULL)
+				TRACEUSER("wuerthne", _T("Ctrl-W pressed"));
+				if (IsNonCharEvent && TextStory::GetFocusStory()->GetCaret()->FindNextTextCharInStory() != NULL)
 				{
 					OpTextFormat* pOp = new OpTextFormat();
 					if (pOp != NULL)
+					{
+						TRACEUSER("wuerthne", _T("DoSwapCase"));
 						pOp->DoSwapCase();
+					}
 					else
 						Errored = TRUE;
 				}
@@ -1388,23 +1421,29 @@
 			// Select all in the focus story, if there is one
 			if (pKeyPress->IsConstrain() && !pKeyPress->IsAdjust())
 			{
-				OpTextSelection* pOp = new OpTextSelection();
-				if (pOp != NULL)
-					Errored = !pOp->DoSelectAllText(TextStory::GetFocusStory());
-				else
-					Errored = TRUE;
+				if (IsNonCharEvent)
+				{
+					OpTextSelection* pOp = new OpTextSelection();
+					if (pOp != NULL)
+						Errored = !pOp->DoSelectAllText(TextStory::GetFocusStory());
+					else
+						Errored = TRUE;
+				}
 				UsedTheKeypress = TRUE;
-			}			   	
+			}
 			break;
 
  		case CAMKEY(V):
 			// Paste text from the clipboard into a selected text story
 			if (pKeyPress->IsConstrain() && !pKeyPress->IsAdjust())
 			{
-				// is there a focus story?
-				OpTextPaste* pOp = new OpTextPaste();
-				if (pOp != NULL)
-					pOp->Do(NULL);
+				if (IsNonCharEvent)
+				{
+					// is there a focus story?
+					OpTextPaste* pOp = new OpTextPaste();
+					if (pOp != NULL)
+						pOp->Do(NULL);
+				}
 				UsedTheKeypress = TRUE;
 			}
 			break;
@@ -1416,11 +1455,14 @@
 				TextLine* pLine = (TextLine*)TextStory::GetFocusStory()->GetCaret()->FindParent(CC_RUNTIME_CLASS(TextLine));
 				if (pLine != NULL)
 				{
-					OpTextSelection* pOp = new OpTextSelection();
-					if (pOp != NULL)
-						Errored = !pOp->DoSelectLineText();
-					else
-						Errored = TRUE;
+					if (IsNonCharEvent)
+					{
+						OpTextSelection* pOp = new OpTextSelection();
+						if (pOp != NULL)
+							Errored = !pOp->DoSelectLineText();
+						else
+							Errored = TRUE;
+					}
 					UsedTheKeypress = TRUE;
 				}
 			}
@@ -1430,7 +1472,7 @@
 			if (pKeyPress->IsConstrain() && !pKeyPress->IsAdjust() )
 			{
 				UsedTheKeypress = TRUE;
-				Errored = !IncreaseTrackKern();
+				Errored = IsNonCharEvent ? !IncreaseTrackKern() : FALSE;
 			}
 			break;
  		case CAMKEY(MINUS):
@@ -1438,29 +1480,36 @@
 			if (pKeyPress->IsConstrain() && !pKeyPress->IsAdjust() )
 			{
 				UsedTheKeypress = TRUE;
-				Errored = !DecreaseTrackKern();
+				Errored = IsNonCharEvent ? !DecreaseTrackKern() : FALSE;
 			}
 			break;
 		case CAMKEY(RETURN):
 			// Create a new TextLine and move the caret to it.
 			if (!pKeyPress->IsAlternative() && !pKeyPress->IsConstrain())
 			{
-				OpTextFormat* pOp = new OpTextFormat();
-				if (pOp != NULL)
-					Errored = !pOp->DoReturn(OpTextFormat::INSERT);
-				else
-					Errored = TRUE;
+				if (IsNonCharEvent)
+				{
+					OpTextFormat* pOp = new OpTextFormat();
+					if (pOp != NULL)
+						Errored = !pOp->DoReturn(OpTextFormat::INSERT);
+					else
+						Errored = TRUE;
+				}
 				UsedTheKeypress = TRUE;
 			}
 			break;
 		case CAMKEY(TAB):
 			if (!pKeyPress->IsAlternative() && !pKeyPress->IsConstrain())
 			{
-				/*##*/
-				OpTextFormat* pOp = new OpTextFormat();
-				if (pOp != NULL)
-					Errored = !pOp->DoTab();
-				else
+				if (IsNonCharEvent)
+				{
+					/* Create a tab node */
+					OpTextFormat* pOp = new OpTextFormat();
+					if (pOp != NULL)
+						Errored = !pOp->DoTab();
+					else
+						Errored = TRUE;
+				}
 				UsedTheKeypress = TRUE;
 			}
 			break;
@@ -1468,13 +1517,16 @@
 			// Deselect the caret and select the text story
 			if (!pKeyPress->IsAlternative() && !pKeyPress->IsConstrain())
 			{
-				pCaret->DeSelect(TRUE);
-				pStory->Select(TRUE);
-				GetApplication()->FindSelection()->Update(TRUE);
+				if (IsNonCharEvent)
+				{
+					pCaret->DeSelect(TRUE);
+					pStory->Select(TRUE);
+					GetApplication()->FindSelection()->Update(TRUE);
+				}
 				UsedTheKeypress = TRUE;
 
 				// Remove the focus story if it was empty
-				Errored = !OpDeleteTextStory::RemoveEmptyFocusStory();
+				Errored = IsNonCharEvent ? !OpDeleteTextStory::RemoveEmptyFocusStory() : FALSE;
 			}
 			break;
 	}
Index: wxOil/textfuns.cpp
===================================================================
--- wxOil/textfuns.cpp	(Revision 1492)
+++ wxOil/textfuns.cpp	(Arbeitskopie)
@@ -639,54 +639,31 @@
 
 CharCase TextManager::ProcessCharCase(WCHAR* pChar, CharCase NewState)
 {
-#ifndef EXCLUDE_FROM_XARALX
 	ERROR2IF(pChar==NULL,Failed,"TextManager::ProcessCharCase() - pChar==NULL");
-	ERROR2IF(NewState==Failed || NewState==Unknown,Failed,"TextManager::ProcessCharCase() - invalid NewState");
+	ERROR2IF(NewState==Failed || NewState==UnknownType,Failed,"TextManager::ProcessCharCase() - invalid NewState");
+	ERROR2IF(sizeof(TCHAR) != sizeof(WCHAR), Failed,"TextManager::ProcessCharCase - Unicode only");
 
-	WCHAR OldCharW = *pChar;
-	CHAR OldCharA = UnicodeManager::UnicodeToMultiByte(OldCharW);
-	CharCase OldCase=Unknown;
+	CharCase OldCase=UnknownType;
 
 	// get a lower case version of the char (if it changes it must have been upper)
+	WCHAR OldCharW = *pChar;
 	WCHAR LowerCharW;
-	if (UnicodeManager::IsUnicodeCompleteOS())
+	if (camTolower(OldCharW) != OldCharW)
 	{
-		WCHAR pLowerChar[2]={OldCharW,0};
-		::CharLowerW(pLowerChar);								
-		if (*pLowerChar != OldCharW)
-			OldCase = Upper;
-		LowerCharW = *pLowerChar;
+		OldCase = Upper;
+		LowerCharW = camTolower(OldCharW);
 	}
-	else
-	{
-		CHAR pLowerChar[2]={OldCharA,0};
-	  	::CharLowerA(pLowerChar);								
-		if (*pLowerChar != OldCharA)
-			OldCase = Upper;
-		LowerCharW = UnicodeManager::MultiByteToUnicode(*pLowerChar);
-	}
 
 	// get an upper case version of the char (if it changes it must have been lower)
 	WCHAR UpperCharW;
-	if (UnicodeManager::IsUnicodeCompleteOS())
+	if (camToupper(OldCharW) != OldCharW)
 	{
-		WCHAR pUpperChar[2]={OldCharW,0};
-		::CharUpperW(pUpperChar);								
-		if (*pUpperChar != OldCharW)
-			OldCase = Lower;
-		UpperCharW = *pUpperChar;
+		OldCase = Lower;
+		UpperCharW = camToupper(OldCharW);
 	}
-	else
-	{
-		CHAR pUpperChar[2]={OldCharA,0};
-	  	::CharUpperA(pUpperChar);								
-		if (*pUpperChar != OldCharA)
-			OldCase = Lower;
-		UpperCharW = UnicodeManager::MultiByteToUnicode(*pUpperChar);
-	}
 
 	// if its case can be changed and we want to change it do it!
-	if (OldCase!=Unknown && NewState!=Read)
+	if (OldCase!=UnknownType && NewState!=Read)
 	{
 		if (NewState==Swap)
 			NewState = OldCase==Lower ? Upper : Lower;
@@ -695,9 +672,6 @@
 	}
 
 	return OldCase;
-#else
-	ERROR2(Failed, "ProcessCharCase NYI");
-#endif
 }