/***************************************************************************** ** Copyright (C) WCH 2001-2023 ** ** Web: http://wch.cn ** ****************************************************************************** Abstract: Edit控件改写,实现十六进制编辑功能 Environment: user mode only,VC6.0 and later Notes: Copyright (c) 2023 Nanjing Qinheng Microelectronics Co., Ltd. SPDX-License-Identifier: Apache-2.0 Revision History: 4/3/2022: V.100 TECH30 --*/ #include "Main.h" #include static BOOL ShiftStatus=FALSE,DelKeyStatus; CHAR DelHexCharIndex,DelHexCharCount; WNDPROC OldEditWndProc; //控件原有窗体程序 ULONG EditCnt=0; //设置插入符形状为黑体 void SetCaretShap(HWND DialogHWND,ULONG CtrlID) { HANDLE iFnt; HDC hdc5; ULONG SelStart,SelEnd; SIZE sz; ULONG width5, height5; CHAR aChar,tem[100]=""; TEXTRANGE txr={0}; HWND CtlHwnd; DestroyCaret(); CtlHwnd = GetDlgItem(DialogHWND,CtrlID); iFnt = (HANDLE)SendDlgItemMessage(DialogHWND,CtrlID,WM_GETFONT,0,0); hdc5 = GetDC(CtlHwnd); SelectObject(hdc5, iFnt); //将字体加入显示场景中 aChar = 0; SendDlgItemMessage(DialogHWND,CtrlID,EM_GETSEL,(ULONG)&SelStart,(ULONG)&SelEnd); txr.chrg.cpMin=SelStart-1; txr.chrg.cpMax=SelStart; txr.lpstrText = &aChar; SendDlgItemMessage(DialogHWND,CtrlID,WM_GETTEXT,10,(ULONG)tem); aChar = tem[0];//tem[SelStart-1]; if(aChar == 0)//可能是在text最後面,所以Caret所在位置没有字元 { if(SelStart > 1) { txr.chrg.cpMin=SelStart-1; txr.chrg.cpMax=SelStart; txr.lpstrText = &aChar; SendDlgItemMessage(DialogHWND,CtrlID,EM_EXGETSEL,0,(ULONG)&txr); } else aChar = 'x'; //内定字元x,选取默认的字体宽高 } GetTextExtentPoint32(hdc5, &aChar, 1, &sz); //取得该字元的长、宽 width5 = sz.cx; height5 = sz.cy; ReleaseDC(DialogHWND, hdc5); CreateCaret(CtlHwnd,NULL,width5, height5);//重新Create Caret ShowCaret(CtlHwnd); //显示Caret } long CALLBACK NewEditWndProc(IN HWND WindowHandle, IN UINT Message, IN WPARAM WParam, IN LPARAM LParam) { ULONG SelStart=0,SelEnd=0,EditCtlId; HWND ParentHwnd; //控件所在窗体句柄 EditCtlId = GetWindowLong(WindowHandle,GWL_ID); ParentHwnd = (HWND)GetWindowLong(WindowHandle,GWL_HWNDPARENT); switch (Message) { case WM_RBUTTONDOWN: case WM_LBUTTONDBLCLK: case WM_LBUTTONDOWN : case WM_LBUTTONUP: case WM_MBUTTONDBLCLK : case WM_MBUTTONDOWN : case WM_MBUTTONUP : { ULONG SelStart,SelEnd,x; SetCaretShap(ParentHwnd,EditCtlId); if( (Message == WM_LBUTTONDOWN)||(Message == WM_MBUTTONDOWN) )//移动mouse时,如果最后一个十六进制只有1个字符时,自动添加一个0 { SendDlgItemMessage(ParentHwnd,EditCtlId,EM_GETSEL,(ULONG)&SelStart,(ULONG)&SelEnd); x = GetWindowTextLength(GetDlgItem(ParentHwnd,EditCtlId)); if( (x>0)&&( (x-1)%3 == 0 )&&(SelStart==x) ) { SendDlgItemMessage(ParentHwnd,EditCtlId,EM_SETSEL,x,x); SendMessage(GetDlgItem(ParentHwnd,EditCtlId),WM_CHAR,(ULONG)'0',1); } } {//如果光标在空格上,自动向后移一个字符 x = GetWindowTextLength(GetDlgItem(ParentHwnd,EditCtlId)); SendDlgItemMessage(ParentHwnd,EditCtlId,EM_GETSEL,(ULONG)&SelStart,(ULONG)&SelEnd); if( (x!=SelStart)&&( !((SelStart+1)%3) ) ) SendDlgItemMessage(ParentHwnd,EditCtlId,EM_SETSEL,SelStart-1,SelEnd-1); } } return (CallWindowProc((WNDPROC)OldEditWndProc,WindowHandle,Message,WParam,LParam)); case WM_CHAR: { CHAR tem[100]=""; CHAR chCharCode = (TCHAR) WParam; // character code ULONG lKeyData = LParam,x; // key data if( !(((chCharCode>='0')&&(chCharCode<='9')) ||//不是有效十六进制字符输入,忽略输入 ((chCharCode>='A')&&(chCharCode<='F')) || ((chCharCode>='a')&&(chCharCode<='f'))) ) { if(chCharCode==VK_BACK) CallWindowProc((WNDPROC)OldEditWndProc,WindowHandle,Message,WParam,LParam); return 0; } SendDlgItemMessage(ParentHwnd,EditCtlId,EM_GETSEL,(ULONG)&SelStart,(ULONG)&SelEnd); x = GetWindowTextLength(GetDlgItem(ParentHwnd,EditCtlId)); if( (x!=SelStart) ) //此是是修改数据,需要提前监视插入符的位置 { if( (SelStart+1)%3 == 0 ) { SendDlgItemMessage(ParentHwnd,EditCtlId,EM_SETSEL,SelStart+1,SelEnd+1); } } SendDlgItemMessage(ParentHwnd,EditCtlId,EM_GETSEL,(ULONG)&SelStart,(ULONG)&SelEnd); //如果用VK_BACK,VK_DELETE键删除字符时,光标停在空格处时自动前移一个,保证不停留在空格前. if( ((SelStart>1)&&( !((SelStart+1)%3)&&(chCharCode!=VK_BACK)&&(chCharCode!=VK_DELETE) ) ) ) { CallWindowProc((WNDPROC)OldEditWndProc,WindowHandle,Message,' ',3735553); } SendDlgItemMessage(ParentHwnd,EditCtlId,EM_GETSEL,(ULONG)&SelStart,(ULONG)&SelEnd); if( (SelStart+1)%3==0 ) SendDlgItemMessage(ParentHwnd,EditCtlId,EM_SETSEL,SelStart+1,SelEnd+1); SendDlgItemMessage(ParentHwnd,EditCtlId,EM_GETSEL,(ULONG)&SelStart,(ULONG)&SelEnd); x = GetWindowTextLength(GetDlgItem(ParentHwnd,EditCtlId)); //如果光标停在空格处,自动移到下一个位置 if(x!=SelEnd) { SendDlgItemMessage(ParentHwnd,EditCtlId,EM_SETSEL,(ULONG)(SelStart+1),(ULONG)(SelEnd) ); } CallWindowProc((WNDPROC)OldEditWndProc,WindowHandle,Message,WParam,LParam); } break; case WM_KEYDOWN: { ULONG x,chCharCode,nVirtKey = (int) WParam; CHAR tem[100]=""; ULONG SelStart,SelEnd; SetCaretShap(ParentHwnd,EditCtlId); chCharCode = nVirtKey; x = GetWindowTextLength(GetDlgItem(ParentHwnd,EditCtlId)); SendDlgItemMessage(ParentHwnd,EditCtlId,EM_GETSEL,(ULONG)&SelStart,(ULONG)&SelEnd); if( (x==SelStart)&&( !((SelStart+1)%3) )&&((nVirtKey==VK_UP)||(nVirtKey==VK_DOWN)) ) SendDlgItemMessage(ParentHwnd,EditCtlId,EM_SETSEL,SelStart-1,SelEnd-1); if( (nVirtKey== VK_RETURN)||(nVirtKey== VK_CONTROL) )//禁用回车和ctrl键 return 0; if( (nVirtKey==VK_LEFT) || (nVirtKey==VK_RIGHT) ||(nVirtKey==VK_UP) || (nVirtKey==VK_DOWN) ||(nVirtKey==VK_HOME) ||(nVirtKey==VK_END) ) { SendDlgItemMessage(ParentHwnd,EditCtlId,EM_GETSEL,(ULONG)&SelStart,(ULONG)&SelEnd); x = GetWindowTextLength(GetDlgItem(ParentHwnd,EditCtlId)); if( ( (x-1)%3 == 0 )&&(SelStart==x) ) { SendDlgItemMessage(ParentHwnd,EditCtlId,EM_SETSEL,x,x); SendMessage(GetDlgItem(ParentHwnd,EditCtlId),WM_CHAR,(ULONG)'0',LParam); //return 0; } } SendDlgItemMessage(ParentHwnd,EditCtlId,EM_GETSEL,(ULONG)&SelStart,(ULONG)&SelEnd); //如果选择VK_BACK键进行数据删除,删除单元是两个十六进制字符加一空格 if( (nVirtKey== VK_BACK) ) { x = GetWindowTextLength(GetDlgItem(ParentHwnd,EditCtlId)); if(!DelHexCharIndex)//删除十六进制字符加空格中的空格 { if(SelStart==0)//在行首,不删除 DelHexCharCount = 0; else if( (x-SelStart)<2 )//在最后一个十六进制字符,保证最后一个字符不是空格 { DelHexCharCount = 2; SelStart+=3; SendDlgItemMessage(ParentHwnd,EditCtlId,EM_SETSEL,(ULONG)SelStart,(ULONG)SelStart); } else if( ((SelStart-1)%3==0) )//插入符正好在两个十六进制字符中间,先移到两个字符后 { SelStart+=2; SendDlgItemMessage(ParentHwnd,EditCtlId,EM_SETSEL,(ULONG)SelStart,(ULONG)SelStart); DelHexCharCount = 3; } else { DelHexCharCount = 3; } SendDlgItemMessage(ParentHwnd,EditCtlId,EM_GETSEL,(ULONG)&SelStart,(ULONG)&SelEnd); if( (SelStart%3)==0 )//插入符正好在十六进制字符前,删除前一个十六进制二个字符加一空格 { PostMessage(GetDlgItem(ParentHwnd,EditCtlId),WM_KEYDOWN,VK_BACK,LParam); DelHexCharIndex++; DelHexCharIndex++; return 0; } } if(DelHexCharIndex=DelHexCharCount )//删除十六进制第一个字符 { DelHexCharIndex = 0; return 0; } } SendDlgItemMessage(ParentHwnd,EditCtlId,EM_GETSEL,(ULONG)&SelStart,(ULONG)&SelEnd); //如果选择VK_DELETE键进行数据删除,删除单元是两个十六进制字符加一空格 if( (nVirtKey== VK_DELETE) ) { if( !DelHexCharIndex )//删除十六进制字符中的第一个字符 { x = GetWindowTextLength(GetDlgItem(ParentHwnd,EditCtlId)); if( (x-SelStart)==1 )//光标停在最后一个字节 { SelStart-=2; } if( (x-SelStart)==2 )//光标停在最后一个字节 { SelStart-=1; } SendDlgItemMessage(ParentHwnd,EditCtlId,EM_SETSEL,(ULONG)SelStart,(ULONG)SelStart); SendDlgItemMessage(ParentHwnd,EditCtlId,EM_GETSEL,(ULONG)&SelStart,(ULONG)&SelEnd); if( !((SelStart-1)%3) )//光标停在十进制数的两个字符的中间 { SelStart-=1; SendDlgItemMessage(ParentHwnd,EditCtlId,EM_SETSEL,(ULONG)SelStart,(ULONG)SelStart); } DelHexCharCount = 3; SendDlgItemMessage(ParentHwnd,EditCtlId,EM_GETSEL,(ULONG)&SelStart,(ULONG)&SelEnd); if( !(SelStart%3) ) { DelHexCharIndex++; PostMessage(GetDlgItem(ParentHwnd,EditCtlId),WM_KEYDOWN,VK_DELETE,LParam); CallWindowProc((WNDPROC)OldEditWndProc,WindowHandle,Message,WParam,LParam); return 0; } } if(DelHexCharIndex=DelHexCharCount )//删除十六进制字符中的空格 { DelHexCharCount = DelHexCharIndex = 0; return 0; } } DelHexCharCount = DelHexCharIndex = 0; SendDlgItemMessage(ParentHwnd,EditCtlId,EM_GETSEL,(ULONG)&SelStart,(ULONG)&SelEnd); if( (nVirtKey== VK_LEFT) )//禁止移到空格前 { if( (SelStart%3)==0 ) { if(!ShiftStatus)//禁止VK_SHIFT+VK_LEFT SendDlgItemMessage(ParentHwnd,EditCtlId,EM_SETSEL,SelStart-1,SelEnd-1); } } if(nVirtKey== VK_RIGHT)//禁止移到空格前 { if( (((SelStart-1)%3)==0) && (SelStart>0) ) { if(!ShiftStatus)//禁止VK_SHIFT+VK_RIGHT SendDlgItemMessage(ParentHwnd,EditCtlId,EM_SETSEL,SelStart+1,SelEnd+1); } } {//禁用SHIFT加VK_LEFT,VK_RIGHT,VK_UP,VK_DOWN if(nVirtKey == VK_SHIFT) //已按下VK_SHIFT { ShiftStatus = TRUE; } if( ShiftStatus && ( ( (nVirtKey>0x24)&&(nVirtKey<0x29) ) || ( nVirtKey == VK_HOME ) || ( nVirtKey == VK_END ) ) ) return 0; } } CallWindowProc((WNDPROC)OldEditWndProc,WindowHandle,Message,WParam,LParam); break; case WM_KEYUP: { ULONG SelStart,SelEnd; int nVirtKey = (int) WParam; if(nVirtKey == VK_SHIFT)//已释放VK_SHIFT { ShiftStatus = FALSE; } if( (((nVirtKey>='0')&&(nVirtKey<='9')) || ((nVirtKey>='A')&&(nVirtKey<='F')) || ((nVirtKey>='a')&&(nVirtKey<='f'))) ) { SendDlgItemMessage(ParentHwnd,EditCtlId,EM_GETSEL,(ULONG)&SelStart,(ULONG)&SelEnd); //如果光标停在空格处,自动移到下一个位置 if(!((SelStart+1)%3))//覆盖数据时,插入符移到空格前时,跳到后一字符前 { SendDlgItemMessage(ParentHwnd,EditCtlId,EM_SETSEL,(ULONG)(SelStart+1),(ULONG)(SelEnd+1) ); } } } CallWindowProc((WNDPROC)OldEditWndProc,WindowHandle,Message,WParam,LParam); break; default: return (CallWindowProc((WNDPROC)OldEditWndProc,WindowHandle,Message,WParam,LParam)); } return 0; } //设置EDIT控件文本输入和十进制输入 VOID SetEditlInputMode( HWND hWnd, // handle of window ULONG CtrlID, //控件ID号 UCHAR InputMode //输入模式:0:文本模式,1:十六进制模式 ) { if ( ( InputMode == 0 ) && ( OldEditWndProc != 0 ) )//文本模式 { SetWindowLong(GetDlgItem(hWnd,CtrlID),GWL_USERDATA,0); SetWindowLong(GetDlgItem(hWnd,CtrlID),GWL_WNDPROC,(LONG)OldEditWndProc); SetDlgItemText(hWnd,CtrlID,""); } else if( InputMode == 1 )//十六进制模式 { OldEditWndProc = (WNDPROC)SetWindowLong(GetDlgItem(hWnd,CtrlID),GWL_WNDPROC,(LONG)NewEditWndProc); SetWindowLong(GetDlgItem(hWnd,CtrlID),DWL_USER,(LONG)CtrlID); SetDlgItemText(hWnd,CtrlID,""); } }