LUA调试环境(三)


QQ 282397369
天下文章一大抄,想在网上找到想要的资料,是得费一番功夫的。
所幸还有技术基础,在明确需求的情况下,总算把目标实现了。

快捷键处理

在前两篇基础上,调试环境首先需要再解决的就是按键处理。
原以为这个很简单,首先发现可直接处理Scintilla的消息。稍微深究一点就知道是WM_NOTIFY消息。查了一下,本功能需求中有用的消息类别处理如下:

void __fastcall TCbwSynEditor::OnEditorMsg(Messages::TMessage & message) {
	if(GetTickCount() - FCreateMoment < 1000)
		return;
	SCNotification *pSCNotification = (SCNotification*)(message.LParam);
	if(pSCNotification->nmhdr.idFrom != SCINT_ID)
		return;
	int iValue;
	switch(pSCNotification->nmhdr.code) {
	case SCN_DOUBLECLICK:
		if(OnEditor_DblClick)
			OnEditor_DblClick(this);
		break;
	case SCN_UPDATEUI:
		if(OnEditor_Click)
			OnEditor_Click(this);
		if(FPaintBox_Assert)
			FPaintBox_Assert->Repaint();
		if(PageControl && PageControl->ActivePage)
			PageControl->ActivePage->Tag = GetCurrentLine();
		break;
	case SCI_SETMARGINSENSITIVEN:
		SendEditor(SCI_TOGGLEFOLD, CurrentLine, 0);
		break;
	case SCN_SAVEPOINTREACHED:   		// SCI_SETSAVEPOINT消息将会触发SCN_SAVEPOINTREACHED事件通知
//		THelper::Debug::AddLog(L"Saved...", clBlue, true);
		FileModified = false;
		break;
	case SCN_SAVEPOINTLEFT: 			// 当文档状态变为modified时,将会触发SCN_SAVEPOINTLEFT事件通知
//		THelper::Debug::AddLog(L"Changed...", clBlue, true);
		FileModified = true;
		break;
	case SCN_MARGINCLICK:
		iValue = SendEditor(SCI_LINEFROMPOSITION, pSCNotification->position);		// 点击位置行号
		if(pSCNotification->margin == 1) {
			SendEditor(SCI_TOGGLEFOLD, iValue);
			Application->ProcessMessages();
			FPaintBox_Assert->Invalidate();
		}
		break;
	case SCN_CHARADDED:
		THelper::Debug::AddLog(THelper::FormatString(L"%d", pSCNotification->ch), clBlue, true);
		break;
	case SCN_KEY:
	case SC_KEYMENU:
		THelper::Debug::AddLog(THelper::FormatString(L"%d", pSCNotification->ch), clBlue, true);
		break;
	default:
		break;
	}
}

当然,纯按键的只是支持SCN_CHARADDED,也就是可以编辑代码。
这里发现一个问题:TAB键、上下左右键无效

TAB键、方向键

查资料发现,可以处理WM_GETDLGCODE消息解决

void __fastcall TCbwSynEditor::OnDlgCode(Messages::TMessage & message) {
	message.Result = DLGC_WANTALLKEYS | DLGC_WANTARROWS | DLGC_WANTTAB;  // 接受方向键和TAB键
}

多费了一点周折而已,还算顺利

F8、F9

但最终卡在F8、F9这两个键上,我的本意是F9可以运行到断点,F8可以单步运行。在上述基础上,无论怎样按F8、F9都不能触发任何事件,稍微多试一下,F1~F12都一样无效。
我在主窗口下测试,都可以触发Form的OnKeyUp事件,其中可以处理F1~F12。
那就只好从VCL的消息机制入手来研究怎样捕获这些消息。这肯定得看VCL中TApplication的消息循环过程中的ProcessMessage函数

function TApplication.ProcessMessage(var Msg: TMsg): Boolean;
var
  Handled: Boolean;
begin
  Result := False;
  if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then
  begin
    Result := True;
    if Msg.Message <> WM_QUIT then
    begin
      Handled := False;
      if Assigned(FOnMessage) then
        FOnMessage(Msg, Handled);
      if not IsHintMsg(Msg) and not Handled and not IsMDIMsg(Msg) and
        not IsKeyMsg(Msg) and not IsDlgMsg(Msg) then
      begin
        TranslateMessage(Msg);
        DispatchMessage(Msg);
      end;
    end
    else
      FTerminate := True;
  end;
end;

再看几个判断函数中,IsKeyMsg是所需要的,即可以在其中进行控制处理

function TApplication.IsKeyMsg(var Msg: TMsg): Boolean;
var
  Wnd: HWND;
begin
  Result := False;
  with Msg do
    if (Message >= WM_KEYFIRST) and (Message <= WM_KEYLAST) then
    begin
      Wnd := GetCapture;
      if Wnd = 0 then
      begin
        Wnd := HWND;
        if (MainForm <> nil) and (Wnd = MainForm.ClientHandle) then
          Wnd := MainForm.Handle
        else
        begin
          // Find the nearest VCL component. Non-VCL windows wont know what
          // to do with CN_BASE offset messages anyway.
          // TOleControl.WndProc needs this for TranslateAccelerator
          while (FindControl(Wnd) = nil) and (Wnd <> 0) do
            Wnd := GetParent(Wnd);
          if Wnd = 0 then
            Wnd := HWND;
        end;
        if SendMessage(Wnd, CN_BASE + Message, WParam, LParam) <> 0 then
          Result := True;
      end
      else if (LongWord(GetWindowLong(Wnd, GWL_HINSTANCE)) = HInstance) then
      begin
        if SendMessage(Wnd, CN_BASE + Message, WParam, LParam) <> 0 then
          Result := True;
      end;
    end;
end;

看IsKeyMsg函数实现逻辑,我所关注的键盘信息应该到SendMessage(Wnd, CN_BASE + Message, WParam, LParam);再找相应的消息类型为CN_KEYDOWN,CN_KEYUP,CN_CHAR,CN_SYSKEYDOWN,CN_SYSCHAR,所以再跟一下CN_KEYUP消息处理

procedure TWinControl.CNKeyDown(var Message: TWMKeyDown);
var
  Mask: Integer;
begin
  with Message do
  begin
    Result := 1;
    UpdateUIState(Message.CharCode);
    if IsMenuKey(Message) then
      Exit;
    if not(csDesigning in ComponentState) then
    begin
      if Perform(CM_CHILDKEY, CharCode, Integer(Self)) <> 0 then
        Exit;
      Mask := 0;
      case CharCode of
        VK_TAB:
          Mask := DLGC_WANTTAB;
        VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN:
          Mask := DLGC_WANTARROWS;
        VK_RETURN, VK_EXECUTE, VK_ESCAPE, VK_CANCEL:
          Mask := DLGC_WANTALLKEYS;
      end;
      if (Mask <> 0) and (Perform(CM_WANTSPECIALKEY, CharCode, 0) = 0) and
        (Perform(WM_GETDLGCODE, 0, 0) and Mask = 0) and
        (GetParentForm(Self).Perform(CM_DIALOGKEY, CharCode, KeyData) <> 0) then
        Exit;
    end;
    Result := 0;
  end;
end;

感觉这里的CM_CHILDKEY消息可以利用一下。试试能否捕获。在Scintilla控件里响应处理:

void __fastcall TCbwSynEditor::OnChildKey(Messages::TMessage & message) {
	WORD Key = message.WParam;
}

结果OK了。
那就加上F8、F9的响应,顺便参考Notepad++实现Alt+1的全部折叠功能

void __fastcall TCbwSynEditor::OnChildKey(Messages::TMessage & message) {
	WORD Key = message.WParam;
	if( (Key == 120 || Key == 119) && FOnSpecialKey)
		FOnSpecialKey(message);
	if(Key == 49 && (GetKeyState(VK_MENU) < 0))  	// alt + 1: 全部折叠
		FoldAll();
}

MDI处理

这个可以最简化的实现,采用PageControl作为标签,选中哪个标签就显示对应的文件内容。唯一需要处理的是记得上次显示的位置。

void __fastcall TCbwSynEditor::OnCloseFile(TObject *Sender, int ATabIndex, bool &ACanClose) {
	UnicodeString fileName = PageControl->Pages[ATabIndex]->Caption.Trim();
	for(int i = 0; i < FFileNames->Count; ++i) {
		UnicodeString fn = FFileNames->Strings[i];
		if(THelper::File::ExtractPureFileName(fn) == fileName) {
			FFileNames->Delete(i);
			Clear();
			i = CAST_RANGE(i, 0, FFileNames->Count - 1);
			if(FFileNames->Count)
				LoadFromFile(FFileNames->Strings[i]);
			break;
		}
	}
}

void __fastcall TCbwSynEditor::OnSelectFile(TObject* Sender) {
	CBW_PREVENT_CHANGE_LOOP;
	int index = PageControl->ActivePageIndex;
	if(index == -1)
		return;
	UnicodeString fileName = PageControl->ActivePage->Hint;
	LoadFromFile(fileName, true);
}

这个没太多值得说的。
在这里插入图片描述

特殊变量内容展示

特殊变量,指图像与XML结构文本

图像

图像通过MAT处理,直接直出在Canvas上即可。

void __fastcall TCbwSynEditor::OnPaintBox_Debug(TObject* Sender) {
	TCanvas * canvas = FPaintBox_Debug->Canvas;
	THelper::Graphics::FillCanvas(canvas, TColor(0xFFEFEF), TColor(0xFFEFEF));
	canvas->Rectangle(0, 0, FPaintBox_Debug->Width, FPaintBox_Debug->Height);

	if(FPaintBox_Debug->Hint == L"MAT") {
		CBW_CAST(TDrMat, drMat, FPaintBox_Debug->Tag);
		cv::Mat mat = drMat->mat;
		if(mat.empty())
			return;
		double height = std::min(mat.rows, FPaintBox_Debug->Height);
		double ratio = height / mat.rows;
		CvHelper::DrawToCanvas(canvas, drMat->mat, TRect(0, 0, mat.cols * ratio, mat.rows * ratio), DRGRAPH_FLAG_FLIP_Y);
	}
}

在这里插入图片描述

XML结构文本

其实,XML与LUA都是文本,直接用Scintilla来表示再好不过。在上面MDI基础上,直接新开一个“调试窗口”即可。
在这里插入图片描述

窗口句柄

这个就一句话,如果想看效果,就直接把该窗口句柄置前。

初步回顾一下,这个LUA调试环境已基本达到预期目标要求。等后续在使用过程中再逐步优化完善。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值