Click here to Skip to main content
15,885,216 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
The problem is that the app doesn't recognise SHIFT t (i.e) CAPITAL T.


Strangely enough when I try to type a capital T in my mfc app nothing happens. If I use Caps Lock it works, but Shift t doesn't work. Initially I thought my keyboard had become faulty, but when I discovered that Shift t works in every other app in my system I started to wonder why.

I try to debug the app, by to find the error, debugging shows that my app's view class/object doesnt receive any OnChar (WM_CHAR) message when shift t keys are depressed. Isn't this the greatest wonder in the world. Please what can be the cause and what can be the solution. In case you are wondering, my app responds to every other characters and character combination?


Okay here are useful information about the app.
1. My document object has (among others) a private data member : TableFigure *m_pEditTableBox ( acceesible by calling : TableFigure * GetEditTable();
2. TableFigure m_pEditTableBox, has (among others),a private data member: Table *m_pTable (accessible by calling: void Table *GetTable();
3.Table *m_pTable has (among others) a data member: TCell *m_ptcell (accessible by calling
TCell *GetEditCell();
4. TCell *m_ptcell has among others, a data member: TableTextFigure *m_pEditText ( accessible by calling TableTextFigure *GetEditTableText();
5. TableTextFigure inherits TextFigure;

C++
#pragma once
#include "..\\Caret.h"
#include "..\\Color.h"
#include "..\\MyFont.h"
#include "Figure.h"

typedef CArray<int> IntArray;
enum KeyboardState {KS_INSERT, KS_OVERWRITE};
enum TextDirection {LEFT_TO_RIGHT,TOP_TO_BOTTOM,BOTTOM_TO_TOP};
enum TextAlignment {TOP_LEFT,TOP_CENTRE,TOP_RIGHT,MIDDLE_LEFT,MIDDLE_CENTRE,MIDDLE_RIGHT,BOTTOM_LEFT,BOTTOM_CENTRE,BOTTOM_RIGHT};

class TextFigure: public Figure
{
  public:
    TextFigure();
    TextFigure(const Color& color, const CPoint& ptMouse,
               const MyFont& font, CDC* pDC);

    TextFigure(const TextFigure& text);
	Figure* Copy() const;

    void Serialize(CArchive& archive);

    BOOL Click(const CPoint& ptMouse);
    BOOL DoubleClick(const CPoint& ptMouse);
    BOOL Inside(const CRect& rcInside) const;

    void MoveOrModify(const CSize& szDistance);
    void Move(const CSize& szDistance);

    virtual BOOL KeyDown(UINT uChar, CDC* pDC);
    virtual void CharDown(UINT uChar, CDC* pDC,KeyboardState eKeyboardState);
    void SetPreviousText(CDC* pDC);

    void Draw(CDC* pDC) const;
    CRect GetArea() const;

	BOOL PointInFigure(const CPoint &ptMouse) const;
	
    MyFont* GetFont() {return &m_font;}
    virtual void SetFont(const MyFont& font, CDC* pDC);
	int GetTextLength() { return m_stText.GetLength();}
	CString GetText() { return m_stText;}
	CString *GetActualText() { return &m_stText;}
	void SetText(CString stText){ m_stText = stText;}
	int *GetEditIndex() { return &m_iEditIndex;}
	//void SetEditIndex(int iIndex){ m_iEditIndex = iIndex;}
	void UpdateCaretArray(CDC *pDC) {GenerateCaretArray(pDC);}
	CPoint GetTextPoint() { return m_ptText;}
	CPoint *GetMyTextPoint() { return &m_ptText;}
	CPoint GetTextInfo(TEXTMETRIC *ptm);
	void MouseDown(const CPoint& ptMouse);
	BOOL PointInText(const CPoint &ptMouse);

	void SetTextDirection(TextDirection eDirection){ m_eTextDirection = eDirection;}
	TextDirection GetTextDirection() { return m_eTextDirection;}
	void SetTextAlignment(TextAlignment eAlignment){ m_eTextAlignment = eAlignment;}
	TextAlignment GetTextAlignment() { return m_eTextAlignment;}

  protected:
    void GenerateCaretArray(CDC* pDC);

  public:
    CRect GetCaretArea(KeyboardState eKeyboardState);
    HCURSOR GetCursor() const;

  private:
    enum {CREATE_TEXT, MOVE_TEXT, EDIT_TEXT, NONE_TEXT} m_eDragMode;

 protected:
    CPoint m_ptText;
    CSize m_szText;

    CString m_stText, m_stPreviousText;
    int m_iAverageWidth;

    MyFont m_font;
    int m_iEditIndex;
    IntArray m_caretArray;

	TextDirection m_eTextDirection;
	TextAlignment m_eTextAlignment;
};


Relevant Textfigure codes are:

C++
BOOL TextFigure::KeyDown(UINT uChar, CDC* pDC)
{
  int iLength = m_stText.GetLength();

  switch (uChar)
  {
    case VK_HOME:
      if (m_iEditIndex > 0)
      {
        m_iEditIndex = 0;
      }
      break;

    case VK_END:
      if (m_iEditIndex < iLength)
      {
        m_iEditIndex = iLength;
      }
      break;

    case VK_LEFT:
      if (m_iEditIndex > 0)
      {
        --m_iEditIndex;
      }
      break;

    case VK_RIGHT:
      if (m_iEditIndex < m_stText.GetLength())
      {
        ++m_iEditIndex;
      }
      break;

    case VK_DELETE:
      if (m_iEditIndex < m_stText.GetLength())
      {
        m_stText.Delete(m_iEditIndex);
        GenerateCaretArray(pDC);
        return TRUE;
      }
      break;

    case VK_BACK:
      if (m_iEditIndex > 0)
      {
        --m_iEditIndex;
        m_stText.Delete(m_iEditIndex);
        GenerateCaretArray(pDC);
        return TRUE;
      }
      break;
  }

  return FALSE;
}


void TextFigure::CharDown(UINT uChar, CDC* pDC, KeyboardState eKeyboardState)
{

  if (m_iEditIndex == m_stText.GetLength())
  {
    m_stText.AppendChar((TCHAR) uChar);
  }

  else
  {
    switch (eKeyboardState)
    {
      case KS_INSERT:
        m_stText.Insert(m_iEditIndex, (TCHAR) uChar);
        break;

      case KS_OVERWRITE:
        m_stText.SetAt(m_iEditIndex, (TCHAR) uChar);
        break;
    }
  }

  ++m_iEditIndex;
  GenerateCaretArray(pDC);
}

void TextFigure::GenerateCaretArray(CDC* pDC)
{
  CFont cFont;
  cFont.CreateFontIndirect(m_font.PointsToMeters());
  CFont* pPrevFont = pDC->SelectObject(&cFont);

  TEXTMETRIC textMetric;
  pDC->GetTextMetrics(&textMetric);
  m_iAverageWidth = textMetric.tmAveCharWidth;

  if (!m_stText.IsEmpty())
  {
    m_szText = pDC->GetTextExtent(m_stText);
  }

  else
  {
    m_szText.SetSize(textMetric.tmAveCharWidth, textMetric.tmHeight);
  }
  //m_szText.SetSize(0, textMetric.tmHeight);  this is the original code
  
  int iWidth = 0, iSize = m_stText.GetLength();
  m_caretArray.SetSize(iSize + 1);

  for (int iIndex = 0; iIndex < iSize; ++iIndex)
  {
    CSize szChar = pDC->GetTextExtent
                        (m_stText.Mid(iIndex, 1));
    m_caretArray[iIndex] = iWidth;
    iWidth += szChar.cx;
  }

  m_caretArray[iSize] = m_szText.cx;
  pDC->SelectObject(pPrevFont);
}

CRect TextFigure::GetCaretArea(KeyboardState eKeyboardState)
{
	CDrawView *pView = CDrawView::GetView();
	CClientDC dc(pView);
	pView->OnPrepareDC(&dc);

	CFont cFont;
	cFont.CreateFontIndirect(m_font.PointsToMeters());
	CFont* pPrevFont = dc.SelectObject(&cFont);

	TEXTMETRIC tm;
	dc.GetTextMetrics(&tm);
	dc.SelectObject(pPrevFont);
	
	switch(m_eTextDirection)
	{
	case LEFT_TO_RIGHT:
		{
		  CPoint ptCaret(m_ptText.x + m_caretArray[m_iEditIndex],m_ptText.y);

		  switch (eKeyboardState)
		  {
			case KS_INSERT:
			  {
				CSize szCaret(1, m_szText.cy);
				return CRect(ptCaret, ptCaret + szCaret);
			  }
			  break;

			  case KS_OVERWRITE:
			  {
				CSize szCaret(m_iAverageWidth, m_szText.cy);
				return CRect(ptCaret, ptCaret + szCaret);
			  }
			  break;
		  }
		}
		break;
	case BOTTOM_TO_TOP:
		{
		  CPoint ptCaret(m_ptText.x ,m_ptText.y + m_caretArray[m_iEditIndex]);

		  switch (eKeyboardState)
		  {
			case KS_INSERT:
			  {
				CSize szCaret(m_szText.cy,1);
				return CRect(ptCaret, ptCaret + szCaret);
			  }
			  break;

			  case KS_OVERWRITE:
			  {
				CSize szCaret(m_szText.cy,m_iAverageWidth);
				return CRect(ptCaret, ptCaret + szCaret);
			  }
			  break;
		  }
		}
		break;
	case TOP_TO_BOTTOM:
		{
		  CPoint ptCaret(m_ptText.x - tm.tmHeight,m_ptText.y - m_caretArray[m_iEditIndex]);

		  switch (eKeyboardState)
		  {
			case KS_INSERT:
			  {
				CSize szCaret(m_szText.cy,1);
				return CRect(ptCaret, ptCaret + szCaret);
			  }
			  break;

			  case KS_OVERWRITE:
			  {
				CSize szCaret(m_szText.cy,m_iAverageWidth);
				return CRect(ptCaret, ptCaret + szCaret);
			  }
			  break;
		  }
		}
		break;
  }

  return CRect();
}


Relevant TableTextFigure codes are:(overrrides TextFigure's draw
C++
#pragma once
#include"..//MyFont.h"
#include"..//Color.h"
#include "TextFigure.h"

class TableTextFigure : public TextFigure
{
 public:
	TableTextFigure();
    TableTextFigure(const Color& color, const CPoint& ptMouse,const MyFont& font, CDC* pDC);

    TableTextFigure(const TableTextFigure &text);
	//TableTextFigure operator =(const TableTextFigure &text);
	Figure* Copy() const;

    void Serialize(CArchive& archive);

    BOOL Click(const CPoint& ptMouse);
    BOOL DoubleClick(const CPoint& ptMouse);
    BOOL Inside(const CRect& rcInside) const;

    void MoveOrModify(const CSize& szDistance);
    void Move(const CSize& szDistance);
	
	void Draw(CDC* pDC) const;
    CRect GetArea() const;
	BOOL PointInFigure(const CPoint &ptMouse) const;

	void SetTextPoint(CPoint &ptText) { m_ptText = ptText;}
	BOOL PointInText(const CPoint &ptMouse) const;
	void SetFont(const MyFont& font, CDC* pDC);
	void SetMyFont(const MyFont& font, CDC* pDC);
	
};

void TableTextFigure::Draw(CDC* pDC) const
{
  CFont cFont;
  cFont.CreateFontIndirect(m_font.PointsToMeters());
  CFont* pPrevFont = pDC->SelectObject(&cFont);

  TEXTMETRIC tm;
  pDC->GetTextMetrics(&tm);

  if (IsMarked() && !pDC->IsPrinting())
  {
     pDC->SetTextColor(WHITE);
     pDC->SetBkColor(BLUE);
	 switch(m_eTextDirection)
	 {
	 case LEFT_TO_RIGHT:
		pDC->TextOut(m_ptText.x, m_ptText.y + m_szText.cy,m_stText);
		break;
	/*case RIGHT_TO_LEFT:
		{
			CString stText;
			CSize szText;
			CPoint ptText = m_ptText;
			int iSize = m_stText.GetLength();
			for(int i = 0; i < iSize; i++)
			{
				stText = m_stText[i];
				szText = pDC->GetTextExtent(stText);
				ptText.x -= szText.cx;
				pDC->TextOut(ptText.x, ptText.y + m_szText.cy,stText);
			}
		}
		break;*/
	 case BOTTOM_TO_TOP:
		 pDC->TextOut(m_ptText.x, m_ptText.y  + tm.tmHeight + tm.tmExternalLeading - m_szText.cy,m_stText);
		break;
	 case TOP_TO_BOTTOM:
		 pDC->TextOut(m_ptText.x, m_ptText.y - tm.tmHeight - tm.tmExternalLeading + m_szText.cy,m_stText);
		break;
	 }
  }
  else
  {
	  pDC->SetTextColor((COLORREF) GetColor());
	  pDC->SetBkColor(WHITE);
	  switch(m_eTextDirection)
	 {
	 case LEFT_TO_RIGHT:
		pDC->TextOut(m_ptText.x, m_ptText.y + m_szText.cy,m_stText);
		break;
	/*case RIGHT_TO_LEFT:
		{
			CString stText;
			CSize szText;
			CPoint ptText = m_ptText;
			int iSize = m_stText.GetLength();
			for(int i = 0; i < iSize; i++)
			{
				stText = m_stText[i];
				szText = pDC->GetTextExtent(stText);
				ptText.x -= szText.cx;
				pDC->TextOut(ptText.x, ptText.y + m_szText.cy,stText);
			}
		}
		break;*/
	 case BOTTOM_TO_TOP:
		 pDC->TextOut(m_ptText.x, m_ptText.y  + tm.tmHeight + tm.tmExternalLeading - m_szText.cy,m_stText);
		break;
	 case TOP_TO_BOTTOM:
		 pDC->TextOut(m_ptText.x, m_ptText.y  - tm.tmHeight - tm.tmExternalLeading + m_szText.cy,m_stText);
		break;
	 }
  }

  pDC->SelectObject(pPrevFont);


The relevant View functions are:
C++
// OnKeyDown is called when the user presses a key at the keyboard.

void CDrawView::OnKeyDown(UINT uChar, UINT /* uRepCnt */, UINT /* uFlags */)
{
  CClientDC dc(this);
  OnPrepareDC(&dc);

  switch (uChar)
  {
    // On home, we scroll to the top left corner.

    case VK_HOME:
      if (!m_pDrawDoc->KeyDown(VK_HOME, &dc))
      {
        OnVScroll(SB_TOP, 0, NULL);
        OnHScroll(SB_LEFT, 0, NULL);
      }
      break;

    // On end, we scroll to bottom right corner.

    case VK_END:
      if (!m_pDrawDoc->KeyDown(VK_END, &dc))
      {
        OnVScroll(SB_BOTTOM, 0, NULL);
        OnHScroll(SB_RIGHT, 0, NULL);
      }
      break;

    // The up and down arrow keys scroll one row.

    case VK_UP:
      OnVScroll(SB_LINEUP, 0, NULL);
      break;

    case VK_DOWN:
      OnVScroll(SB_LINEDOWN, 0, NULL);
      break;

    // In case the left or right arrow key was not used to edit a text, we
    // scroll one line.

    case VK_LEFT:
      if (!m_pDrawDoc->KeyDown(VK_LEFT, &dc))
      {
        OnHScroll(SB_LINELEFT, 0, NULL);
      }
      break;

    case VK_RIGHT:
      if (!m_pDrawDoc->KeyDown(VK_RIGHT, &dc))
      {
        OnHScroll(SB_LINERIGHT, 0, NULL);
      }
      break;

    // In case of the page up or page down key, we just scroll the bars.

    case VK_PRIOR:
      OnVScroll(SB_PAGEUP, 0, NULL);
      break;

    case VK_NEXT:
      OnVScroll(SB_PAGEDOWN, 0, NULL);
      break;

    // In case of the insert, delete, backspace, return, or escape key,
    // we call KeyDown in the document class.

    case VK_INSERT:
    case VK_DELETE:
    case VK_BACK:
    case VK_RETURN:
    case VK_ESCAPE:
      m_pDrawDoc->KeyDown(uChar, &dc);
      break;
  }
}

// OnChar is called when the user presses a printable character (ASCII table
// value 32 – 122). It calls CharDown in the document class.

void CDrawView::OnChar(UINT uChar, UINT /* uRepCnt */, UINT /* uFlags */)
{
  CClientDC dc(this);
  OnPrepareDC(&dc);

  m_pDrawDoc->CharDown(uChar, &dc);
}


The relevant Document functions are:
C++
BOOL CDrawDoc::KeyDown(UINT uChar, CDC* pDC)
{
 if (uChar == VK_INSERT)
  {
    if (m_eKeyboardState == KS_INSERT)
    {
      m_eKeyboardState = KS_OVERWRITE;
    }
    else
    {
      m_eKeyboardState = KS_INSERT;
    }

    if(m_eApplicationState == EDIT_TABLETEXT)
    {
      CRect rcCaret = m_pEditTextBox->GetCaretArea(m_eKeyboardState);
      m_caret.SetAndShowCaret(rcCaret);
    }

    return TRUE;
  }IT_TEXTBOX)
    {
      CRect rcCaret = m_pEditTextBox->GetCaretArea(m_eKeyboardState);
      m_caret.SetAndShowCaret(rcCaret);
    }

	 if(m_eApplicationState == EDIT_TABLETEXT)
    {
      CRect rcCaret = m_pEditTextBox->GetCaretArea(m_eKeyboardState);
      m_caret.SetAndShowCaret(rcCaret);
    }

    return TRUE;
  }IT_TEXTBOX)
    {
      CRect rcCaret = m_pEditTextBox->GetCaretArea(m_eKeyboardState);
      m_caret.SetAndShowCaret(rcCaret);
    }

	 if(m_eApplicationState == EDIT_TABLETEXT)
    {
      CRect rcCaret = m_pEditTextBox->GetCaretArea(m_eKeyboardState);
      m_caret.SetAndShowCaret(rcCaret);
    }

    return TRUE;
  }


  if (m_eApplicationState ==  EDIT_TABLETEXT)
   {
    switch (uChar)
    {
      case VK_LEFT:
      case VK_RIGHT:
      case VK_HOME:
      case VK_END:
      case VK_DELETE:
      case VK_BACK:
	  case VK_RETURN:
	     {
          // If there is an editing character, we edit the text and set the
          // modified flag if the KeyDown method returns true.

          CRect rcOldText = m_pEditTableBox->GetArea();
          BOOL bModified = m_pEditTableBox->KeyDown(uChar, pDC);

          if (bModified)
          {
              SetModifiedFlag();
          }

          // We update the text and the caret.

          CRect rcNewText = m_pEditTableBox->GetArea();
          UpdateAllViews(NULL, (LPARAM) &rcOldText);
          UpdateAllViews(NULL, (LPARAM) &rcNewText);
		 
		  CRect rcCaret = m_pEditTableBox->GetCaretArea(m_eKeyboardState);
          m_caret.SetAndShowCaret(rcCaret);
         
        }
        break;

	 case VK_ESCAPE:
        {
          CRect rcText = m_pEditTableBox->GetArea();
          m_pEditTableBox->Mark(FALSE);

          UpdateAllViews(NULL, (LPARAM) &rcText);
          m_caret.HideCaret();

          m_pEditTableBox = NULL;
          m_eApplicationState = IDLE;
		  m_eNextActionState = MODIFY_FIGURE;
        }
        break;
     
      }

      return TRUE;
    
  }
  
  // If the application is in modifying mode and at least one figure is
  // marked, we simulate the menu option Delete.

  int iMarked = m_figurePtrList.CountIf(IsMarked);
  if ((uChar == VK_DELETE) && (iMarked > 0))
  {
    OnDelete();
    return TRUE;
  }

  // In case of a key different from those handled so far, we just return
  // false.

  return FALSE;
}

void CDrawDoc::CharDown(UINT uChar, CDC* pDC)
{
 
   if ((m_eApplicationState == EDIT_TABLETEXT) && isprint(uChar))
  {
	  m_caret.HideCaret();
	  if(m_pEditTableBox->GetTable()->GetEditCell()->GetCaretFlag())
	  {
		  return;
	  }
	 
	  try
	  {
		m_pEditTableBox->CharDown(uChar, pDC, m_eKeyboardState);
	  }
	  catch(BOOL bSkip)
	  {
		  m_pEditTableBox->GetTable()->GetEditCell()->SetCaretFlag(bSkip);
		  return;
	  }

	  CRect rcText = m_pEditTableBox->GetArea();
     
	  CRect rcCaret = m_pEditTableBox->GetCaretArea(m_eKeyboardState);
	  m_caret.SetAndShowCaret(rcCaret);
      
	  UpdateAllViews(NULL, (LPARAM) &rcText);
	  
	  SetModifiedFlag();
   }
}


The prototype of relevant TableFigure,Table, TCell,TableText classes are all the same:All each does to call get the relvant data member functions whicha are all public function: A sample prototype for TCell is shown below:

C++
void TCell::CharDown(UINT uChar, CDC *pDC, KeyboardState m_eKeyboardState)
BOOL TCell::KeyDown(UINT uChar, CDC* pDC)


So what really happens in the code is that, The view class calls the document class; the document class class calls its CharDown function and its CharDown function call the CharDown function of the Tablefigure object which goes on to eventually call the CharDown figure of the TableTextFigure.


So, what could be wrong
Posted

1 solution

WM_CHAR does not handle shift - you would need to handle WM_KEYDOWN to spot shift and / or control.
WM_KEYDOWN handles the raw keys, WM_CHAR handles the processed keys.

If you look here: http://msdn.microsoft.com/en-gb/library/windows/desktop/gg153546(v=vs.85).aspx[^] it explains it:
For example, suppose the user presses the SHIFT key followed by the A key. Assuming a standard keyboard layout, you would get the following sequence of messages:
WM_KEYDOWN: SHIFT
WM_KEYDOWN: A
WM_CHAR: 'A'
 
Share this answer
 
Comments
Gbenbam 10-Sep-14 6:59am    
OK.Thanks.I'II look into it.
Gbenbam 10-Sep-14 7:24am    
This is in no way a rejection of your valid solution.I was just wondering why my app recognises SHIFT plus other letters.i.e capitalization of other letters
OriginalGriff 10-Sep-14 8:23am    
Because they are handled as part of KEYDOWN, and included in the character passed to CHAR:
A + [SHIFT] passes 'A'
A + [no shift] passes 'a'
Gbenbam 10-Sep-14 12:25pm    
Then is my app singling out capital key .I mean why would it handle every other capital letters and not capital t.It is really a source of wonder to me.
Gbenbam 10-Sep-14 12:33pm    
Thanks a lot.I'II just set a flag during d shift case of my WM_KEYDOWN case of and render the character upper in my WM_CHAR case if d shift flag is set.Once again thanks.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900