JBoolean
CBVIKeyHandler::HandleKeyPress
	(
	const JCharacter				key,
	const JBoolean					selectText,
	const JTextEditor::CaretMotion	motion,
	const JBoolean					deleteToTabStop
	)
{
	JBoolean result;
	if (PrehandleKeyPress(key, &result))
		{
		return result;
		}

	if (key == ':')
		{
		SetMode(kCommandLineMode);
		return kJTrue;
		}
	else if (GetMode() == kCommandLineMode && GetCommandLine().IsEmpty() &&
			 isdigit(key) && key != '0')
		{
		CBTELineIndexInput* field = itsCBTE->GetLineInput();
		field->Focus();

		const JCharacter s[2] = { key, '\0' };
		field->SetText(s);
		field->GoToEndOfLine();

		SetMode(kCommandMode);
		return kJTrue;
		}
	else if (GetMode() == kCommandLineMode && key == '\n')
		{
		CBTextDocument* doc = itsCBTE->GetDocument();
		const JString& buf  = GetCommandLine();
		if (buf == "0")
			{
			itsCBTE->SetCaretLocation(1);
			}
		else if (buf == "$")
			{
			itsCBTE->SetCaretLocation(itsCBTE->GetTextLength()+1);
			}
		else if (buf == "w" || buf == "w!")
			{
			doc->SaveInCurrentFile();
			}
		else if (buf == "q")
			{
			doc->Close();
			return kJTrue;
			}
		else if (buf == "q!")
			{
			doc->DataReverted(kJTrue);
			doc->Close();
			return kJTrue;
			}
		else if (buf == "wq")
			{
			doc->SaveInCurrentFile();
			doc->Close();
			return kJTrue;
			}

		SetMode(kCommandMode);
		return kJTrue;
		}
	else if (GetMode() == kCommandLineMode)
		{
		AppendToCommandLine(key);
		return kJTrue;
		}

	else
		{
		return JXVIKeyHandler::HandleKeyPress(key, selectText, motion, deleteToTabStop);
		}
}
JBoolean
JVIKeyHandler::HandleKeyPress
	(
	const JCharacter				key,
	const JBoolean					selectText,
	const JTextEditor::CaretMotion	motion,
	const JBoolean					deleteToTabStop
	)
{
	JBoolean result;
	if (PrehandleKeyPress(key, &result))
		{
		return result;
		}

	if (key == kJLeftArrow || key == kJRightArrow ||
		key == kJUpArrow || key == kJDownArrow)
		{
		ClearKeyBuffers();
		return kJFalse;
		}

	JTextEditor* te = GetTE();

	JBoolean clearKeyBuffer = kJTrue;
	JArray<JIndexRange> matchList;
	JCharacter prevChar;
	if (key == 'i')
		{
		SetMode(kTextEntryMode);
		}
	else if (key == 'I')
		{
		SetMode(kTextEntryMode);

		const JBoolean save = te->WillMoveToFrontOfText();
		te->ShouldMoveToFrontOfText(kJTrue);
		te->GoToEndOfLine();
		te->GoToBeginningOfLine();
		te->ShouldMoveToFrontOfText(save);
		}
	else if (key == 'a')
		{
		SetMode(kTextEntryMode);
		const JIndex i = te->GetInsertionIndex();
		if (te->IndexValid(i) && (te->GetText()).GetCharacter(i) != '\n')
			{
			te->SetCaretLocation(te->GetInsertionIndex()+1);
			}
		}
	else if (key == 'A')
		{
		SetMode(kTextEntryMode);
		te->GoToEndOfLine();
		}
	else if (key == 'O')
		{
		SetMode(kTextEntryMode);

		te->GoToBeginningOfLine();
		const JIndex i = te->GetInsertionIndex();
		te->SetCaretLocation(i-1);
		InsertKeyPress('\n');
		if (i == 1)
			{
			te->SetCaretLocation(1);
			}
		}
	else if (key == 'o')
		{
		SetMode(kTextEntryMode);

		te->GoToEndOfLine();
		InsertKeyPress('\n');
		}

	else if ((key == '0' || key == '^') && itsKeyBuffer.IsEmpty())
		{
		te->GoToBeginningOfLine();
		}
	else if (key == '\n')
		{
		MoveCaretVert(1);

		const JBoolean save = te->WillMoveToFrontOfText();
		te->ShouldMoveToFrontOfText(kJTrue);
		te->GoToEndOfLine();
		te->GoToBeginningOfLine();
		te->ShouldMoveToFrontOfText(save);
		}
	else if (key == 'G')
		{
		te->SetCaretLocation(te->GetTextLength()+1);
		}

	else if (isdigit(key))	// after 0 => beginning of line
		{
		if (!numberPattern.Match(itsKeyBuffer))
			{
			ClearKeyBuffers();
			}
		itsKeyBuffer.AppendCharacter(key);
		clearKeyBuffer = kJFalse;
		}
	else if (key == '"')
		{
		itsMode = kBufferNameMode;		// don't use SetMode()
		itsKeyBuffer.AppendCharacter(key);
		clearKeyBuffer = kJFalse;
		}
	else if (key == 'X' || key == 'x')
		{
		CutBuffer* buf = GetCutBuffer(cutbufPattern);
		buf->Set("", kJFalse);

		const JSize count = GetOperationCount();
		JString s;
		for (JIndex i=1; i<=count; i++)
			{
			if (key == 'X')
				{
				if (te->GetInsertionIndex() == 1)
					{
					break;
					}
				BackwardDelete(deleteToTabStop, &s);
				}
			else
				{
				if (te->GetInsertionIndex() >= te->GetTextLength())
					{
					break;
					}
				ForwardDelete(deleteToTabStop, &s);
				}

			buf->buf->Append(s);
			}
		}
	else if (key == 'C' || key == 'D' ||
			 (key == '$' && GetPrevCharacter(&prevChar) &&
			  (prevChar == 'd' || prevChar == 'y')))
		{
		const JBoolean del = JNegate(GetPrevCharacter(&prevChar) && prevChar == 'y' && key == '$');
		YankToEndOfLine(del, JI2B(key == 'C'));
		}
	else if ((key == 'Y' || key == 'y' || key == 'd') &&
			 yankDeletePattern.Match(itsKeyBuffer, &matchList))
		{
		if (key == 'Y' ||
			(GetPrevCharacter(&prevChar) && prevChar == key))
			{
			YankLines(matchList, JI2B(key == 'd'));
			}
		else
			{
			itsKeyBuffer.AppendCharacter(key);
			clearKeyBuffer = kJFalse;
			}
		}

	else if (key == 'P' || key == 'p')
		{
		CutBuffer* buf = GetCutBuffer(cutbufPattern);
		if (buf->buf != NULL)
			{
			const JIndex i = te->GetInsertionIndex();
			if (buf->line)
				{
				te->GoToBeginningOfLine();
				if (key == 'p')
					{
					MoveCaretVert(1);
					}
				}
			else if (key == 'p' &&
					 (te->IndexValid(i) && (te->GetText()).GetCharacter(i) != '\n'))
				{
				te->SetCaretLocation(te->GetInsertionIndex()+1);
				}

			const JSize count = GetOperationCount();
			for (JIndex i=1; i<=count; i++)
				{
				te->Paste(*(buf->buf));
				}
			}
		}

	else if (key == 'u')
		{
		te->Undo();
		}

	else if (key == '$')	// after d$ and y$
		{
		te->GoToEndOfLine();
		const JIndex i = te->GetInsertionIndex();
		if (i > 1 && te->IndexValid(i) &&
			(te->GetText()).GetCharacter(i) == '\n')
			{
			te->SetCaretLocation(i-1);
			}
		}

	if (clearKeyBuffer)
		{
		ClearKeyBuffers();
		}
	return kJTrue;
}