LUA调试环境(三)
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调试环境已基本达到预期目标要求。等后续在使用过程中再逐步优化完善。
DrGraph 原创文章 14获赞 3访问量 1378 关注 私信- lua 5.3开发调试环境搭建
- 如何在vs (visual studio)调试环境下查看lua的调用栈、变量信息
- Lua开发环境和调试工具
- 【有用】Lua cocos2dx (quick cocos2d x ) Lua调试开发环境搭建资源总结
- lua 5.3开发调试环境搭建
- lua的VS或者VC环境的搭建调试
- 如何在vs (visual studio)调试环境下查看lua的调用栈、变量信息
- Cocos2d-x lua 3.x VS集成Babelua 环境搭建与代码调试
- [Lua] Lua学习笔记(一) 安装调试环境
- vs2010和zbStudio远程调试c和lua开发环境搭建
- Lua cocos2dx (quick cocos2d x ) Lua调试开发环境搭建资源总结
- Windows下lua+redis调试环境搭建
- cocos2dx 3.10 lua环境配置与代码调试
- Cocos2d-Lua VS调试环境
- cocos2dx 3.12 lua环境配置与代码调试_02
- VS2013调试lua环境搭建
- cocos2dx 3.10 lua环境配置与代码调试
- 初识 love2d. Hello World & lua 调试 & iOS 环境运行
- spark windows开发调试环境
- VSCode配置python调试环境