Погружаясь в скриптовую автоматизацию AkelPad, я пришел к мысли, что не плохо было бы как-то удобизировать работу с C-структурами, и в итоге написал "фабричную" функцию, создающую обекты-врапперы структур, в которых методы соответствуют полям структур и реализуют запись/чтение этих полей.. Также я написал уже функцию, которая, на основе сишных определений структур в тексте, создает соответствующие "фабрики" объектов - врапперов этих структур. Реализацию и пример использования можно найти [ur=https://github.com/LAcoder2/AkelPadScriptsl]здесь[/url] (файлы MemHelp.js, StructTest,js, RegisterHotkeyExample.js, ExampleEvents.js). Вишенкой на торте хотелось бы дополнить реализацией кастомного списка автозамены, который должен появиться когда вводишь точку в редакторе после имени объекта - враппера структуры.. Обработку событий ввода я уже реализовал в файле ExampleEvents.js. Окно списка автозамены хотелось бы взять стандартное из плагина Coder, которое можно вызвать командой
AkelPad.Call("Coder::AutoComplete::WithList")
Вопрос - реално ли в JS реализовать хук этого окна и заполнение его своими значениями, при этом использя внутренние структуры Сoder-а, чтобы не нарушать его работу? Или лучше делать собственную реализацию этого списка на JScript?
Свой список автозамены
- Author
- Message
-
Offline
- Posts: 14
- Joined: Tue Feb 03, 2026 1:20 pm
Re: Свой список автозамены
После двух дней мучений с нейросетью получилось выкатить только вот эту "деревяшку". Оно появляется там где нужно, но ни чего не делает.
Изначально я давал нейросетке рабочий пример но с другим окном где логика создания и обработки окна инкапсулирована в единой функции, и велел делать также, но "железный истукан" не стал соблюдать мой шаблон. Боль и плач.
Изначально я давал нейросетке рабочий пример но с другим окном где логика создания и обработки окна инкапсулирована в единой функции, и велел делать также, но "железный истукан" не стал соблюдать мой шаблон. Боль и плач.
Code: Select all
// AutoCompletePopup.js
AkelPad.Include("MemHelp.js")
AkelPad.Include("log.js")
var oSys = AkelPad.SystemFunction()
var hMainWnd = AkelPad.GetMainWnd()
var hInstDLL = AkelPad.GetInstanceDll()
var sClass
var MessageLoopOwnFlag
var gPopup = {hWnd:0, hLB:0, hEdit:0, aItems:[]}
if (!AkelPad.IsInclude())
ShowAutoCompletePopup(["Яблоко", "Груша", "Апельсин"], 0)
function ShowAutoCompletePopup(aItems, hEdit){
gPopup.aItems = aItems
gPopup.hEdit = hEdit || AkelPad.GetEditWnd()
if (!gPopup.hEdit) return
sClass = "AkelPad::AutoCompletePopup::" + hInstDLL
if (hDlg = oSys.Call("User32::FindWindowExW", 0, 0, sClass, 0)){
oSys.Call("User32::SetForegroundWindow", hDlg)
return
}
var caretPos = GetCaretPos(gPopup.hEdit)
var nX = caretPos.X
var nY = caretPos.Y + AkelPad.SendMessage(gPopup.hEdit, 3188, 0, 0)
AkelPad.WindowRegisterClass(sClass)
// WS_POPUP | WS_VISIBLE | WS_BORDER | WS_CLIPSIBLINGS (0x90800000)
// WS_EX_CLIENTEDGE (0x00000200) даёт одинаковую границу по всему контуру, без заголовка
gPopup.hWnd = oSys.Call("User32::CreateWindowExW",
0x00000200,
sClass, "",
0x90800000,
nX, nY, 180, 120,
hMainWnd, 0, hInstDLL, DialogCallback)
if (!gPopup.hWnd){
AkelPad.WindowUnregisterClass(sClass)
return
}
oSys.Call("User32::ShowWindow", gPopup.hWnd, 1)
SetForegroundWindow(gPopup.hWnd)
if (!AkelPad.ScriptHandle(0, 13)){
MessageLoopOwnFlag = true
AkelPad.WindowGetMessage()
MessageLoopOwnFlag = false
AkelPad.WindowUnregisterClass(sClass)
}
}
function DialogCallback(hWnd, uMsg, wParam, lParam){
switch(uMsg){
case 1: // WM_CREATE
gPopup.hLB = oSys.Call("User32::CreateWindowExW",
0, "LISTBOX", "",
0x50000000 | 0x00000002 | 0x00000040, // WS_CHILD|WS_VISIBLE|LBS_NOTIFY|LBS_NOINTEGRALHEIGHT
2, 2, 172, 112,
hWnd, 1001, hInstDLL, 0)
var hFont = AkelPad.SendMessage(gPopup.hEdit, 0x0031, 0, 0)
if (hFont) AkelPad.SendMessage(gPopup.hLB, 0x0030, hFont, true)
for (var i=0; i<gPopup.aItems.length; i++)
AkelPad.SendMessage(gPopup.hLB, 0x0180, 0, gPopup.aItems[i])
AkelPad.SendMessage(gPopup.hLB, 0x018E, 0, 0)
return 0
case 273: // WM_COMMAND
var nID = wParam & 0xFFFF
var nCode = (wParam >>> 16) & 0xFFFF
// 2 = LBN_DBLCLK, 1 = LBN_SELCHANGE. Используем двойной клик, чтобы не закрывать при навигации стрелками
if (nID == 1001 && nCode == 2){
DoInsertAndClose()
return 0
}
return 0
case 0x0100: // WM_KEYDOWN
if (wParam == 13){ // VK_RETURN
DoInsertAndClose()
return 0
}
if (wParam == 27){ // VK_ESCAPE
ClosePopup()
return 0
}
return 0
case 0x0008: // WM_KILLFOCUS
ClosePopup()
return 0
case 16: // WM_CLOSE
oSys.Call("User32::DestroyWindow", hWnd)
return 0
case 2: // WM_DESTROY
gPopup.hWnd = 0
gPopup.hLB = 0
if (MessageLoopOwnFlag) oSys.Call("User32::PostQuitMessage", 0)
return 0
}
return 0
}
function DoInsertAndClose(){
if (!gPopup.hLB) return
var nSel = AkelPad.SendMessage(gPopup.hLB, 0x0188, 0, 0) // LB_GETCURSEL
if (nSel == -1) return
var nLen = AkelPad.SendMessage(gPopup.hLB, 0x018D, nSel, 0) // LB_GETTEXTLEN
if (nLen <= 0 || nLen > 32768) return
var sBuf = makeStrBuff(nLen + 1)
var lpBuf = AkelPad.MemStrPtr(sBuf)
AkelPad.SendMessage(gPopup.hLB, 0x0189, nSel, lpBuf) // LB_GETTEXT
var sText = sBuf.replace(/\0+$/, "")
oSys.Call("User32::SetFocus", gPopup.hEdit)
AkelPad.ReplaceSel(sText)
ClosePopup()
}
function ClosePopup(){
if (gPopup.hWnd && oSys.Call("User32::IsWindow", gPopup.hWnd))
oSys.Call("User32::PostMessageW", gPopup.hWnd, 16, 0, 0)
}
// --- Вспомогательные функции (без изменений, как в вашем шаблоне) ---
function GetCaretPos(hEdit){
var sPointBuf = makeStrBuff(4)
var lpPoint = sPointBuf.StrPtr()
return (GetCaretPos = function(hEdit){
if (!hEdit) hEdit = AkelPad.GetEditWnd()
AkelPad.SendMessage(hEdit, 0x00D6, lpPoint, AkelPad.GetSelStart())
oSys.Call("User32::ClientToScreen", hEdit, lpPoint)
return {
X: AkelPad.MemRead(lpPoint, 3),
Y: AkelPad.MemRead(_PtrAdd(lpPoint, 4), 3)
}
})(hEdit)
}
function SetForegroundWindow(hWnd){
if (oSys.Call("User32::IsIconic", hWnd)) oSys.Call("User32::ShowWindow", hWnd, 9)
oSys.Call("User32::SetForegroundWindow", hWnd)
}