Погружаясь в скриптовую автоматизацию 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: 17
- 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)
}-
Offline
- Posts: 17
- Joined: Tue Feb 03, 2026 1:20 pm
Re: Свой список автозамены
Почти достиг того что мне нужно, но не смог пока побороть Enter, который проходит через блокирующий обработчик и проскакивает в редактор. Т.е., допустим, выбрал я пункт в списке нажимаю Enter (Enter еренаправляется окно попап-списка), этот пункт вставляется вредактор, но происходит так, то пункт вставляется с переносом на новую строку, хотя отловил Enter в сабклассе перенаправил в список, блокировал его дальнейшую обработку в редакторе с помощью WindowNoNextProc, но нет, он все равно проскаивает в редактор, гадина такая!
Code: Select all
AkelPad.Include("MemHelp.js")
AkelPad.Include("log.js")
AkelPad.Include("timer.js")
AkelPad.Include("Coder.js") // для Stop- StartRedraw()
var oSys = AkelPad.SystemFunction()
var hMainWnd = AkelPad.GetMainWnd()
var hInstDLL = AkelPad.GetInstanceDll()
var sClass
var MessageLoopOwnFlag
var shtdTaskFlag
var oPopup = {hWnd:0, hLB:0, hEdit:0, aItems:[]}
// Тестовый запуск
if (!AkelPad.IsInclude())
ShowAutoCompletePopup(["Яблоко", "Груша", "Апельсин", "Банан", "Вишня", "Дыня", "Ежевика", "Жимолость", "Земляника", "Ирга"])
//var ticCount = oSys.Call("kernel32::GetTickCount")
function ShowAutoCompletePopup(aItems){
var hWndEdit
oPopup.aItems = aItems
oPopup.hEdit = AkelPad.GetEditWnd()
if (!oPopup.hEdit) return
sClass = "AkelPad::AutoCompletePopup::" + hInstDLL
if (hDlg = oSys.Call("User32::FindWindowExW", 0, 0, sClass, 0)){
//SetForegroundWindow(hDlg)
return
}
AkelPad.WindowRegisterClass(sClass)
return (ShowAutoCompletePopup = function (aItems){
hWndEdit = AkelPad.GetEditWnd()
var caretPos = GetCaretPos(oPopup.hEdit)
var nX = caretPos.X
var nY = caretPos.Y + AkelPad.SendMessage(oPopup.hEdit, 3188/*AEM_GETCHARSIZE*/, 0, 0)
oPopup.hWnd = oSys.Call("User32::CreateWindowExW",
0x00000080 | 0x08000000, // WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE (критично: не забирает фокус у редактора)
sClass, "",
//WS_POPUP | WS_VISIBLE | WS_THICKFRAME
0x80000000 | 0x10000000 | 0x00040000,
nX, nY, 220, 200,
hMainWnd, 0, hInstDLL, DialogCallback)
if (!oPopup.hWnd){
AkelPad.WindowUnregisterClass(sClass)
return
}
// Показываем без активации (SW_SHOWNOACTIVATE = 4) ~ но все равно активируется, кстати ~
//StopRedraw()
oSys.Call("User32::ShowWindow", oPopup.hWnd, 4)
//StartRedraw()
oSys.Call("User32::SetFocus", AkelPad.GetEditWnd()) // возвращаем фокус в окно редактора, чтобы не терять вомзможность ввода
// Поднимаем в Z-порядке, но НЕ активируем
//oSys.Call("User32::SetWindowPos", oPopup.hWnd, -2, 0, 0, 0, 0, 0x0001 | 0x0002 | 0x0010)
//oSys.Call("User32::SetFocus", AkelPad.GetEditWnd())
// Выделяем первый элемент по умолчанию (как в Coder)
//oSys.Call("User32::SetFocus", oPopup.hLB)
// Отложенная инициализация выделения первого пункта
//oSys.Call("User32::PostMessageW", oPopup.hWnd, 0x8000/*WM_APP*/, 0, 0)
if (!AkelPad.ScriptHandle(0, 13)){
MessageLoopOwnFlag = true
AkelPad.WindowGetMessage()
MessageLoopOwnFlag = false
AkelPad.WindowUnregisterClass(sClass)
} else {
if (!shtdTaskFlag) {
shutdownTasks.add(function (){
AkelPad.WindowUnregisterClass(sClass)
})
shtdTaskFlag = true
}
}
})(aItems)
var hWndEditSubClass
function EditCallback(hWnd, uMsg, wParam, lParam){
if (uMsg == 0x0202/*WM_LBUTTONUP*/){ // если был клик в произвольной области окна редактора
AkelPad.WindowNextProc(hWndEditSubClass, hWnd, uMsg, wParam, lParam)
ClosePopup() // то закрываем попап
} else if (wParam == 13/*VK_RETURN*/ || wParam == 27/*VK_ESCAPE*/ || wParam == 38/*VK_UP*/ || wParam == 40/*VK_DOWN*/){
//PrintLog('hWndEditSubClass = ' + hWndEditSubClass)
oSys.Call("User32::PostMessageW", oPopup.hLB, uMsg, wParam, lParam)// перенаправляем сообщение в попап-листбокс
//PrintLog('wParam = ' + wParam)
AkelPad.WindowNoNextProc(hWndEditSubClass) // Блокируем дальнейшую обработку
//oSys.Call("User32::PostMessageW", oPopup.hLB, 0x0100/*WM_KEYDOWN*/, 40/*VK_DOWN*/, 0)
//oSys.Call("User32::SetFocus", hWnd)
return 1 // обработано
}
return 0
}
var oDIS, sRect, lpRect, oRect // стек сохраняемых данных функции DialogCallback
function DialogCallback(hWnd, uMsg, wParam, lParam){
var WM_MOUSEACTIVATE = 33
var MA_NOACTIVATE = 3
var WM_NCACTIVATE = 0x86 // 134
//return (DialogCallback = function (hWnd, uMsg, wParam, lParam){
switch(uMsg){
/*switch (uMsg){
case 32: break
case 132: break
case 160: break
case 512: break
default:
PrintLog('uMsg = ' + uMsg + ' wParam = ' + wParam)
break
}*/
case 1: // WM_CREATE
oPopup.hLB = oSys.Call("User32::CreateWindowExW",
0x00000200, // WS_EX_CLIENTEDGE
"LISTBOX", "",
/*WS_CHILD | WS_VISIBLE | WS_VSCROLL | LBS_NOTIFY | LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS*/
0x40000000 | 0x10000000 | 0x00200000 | 0x00000001 | 0x00000100 | 0x00001000/* | 0x0010 | 0x0040*/,
/*2, 2*/0, 0, 212, 192,
hWnd, 1001, hInstDLL, 0)
var hFont = AkelPad.SendMessage(oPopup.hEdit, 0x0031/*WM_GETFONT*/, 0, 0)
if (hFont) AkelPad.SendMessage(oPopup.hLB, 0x0030/*WM_SETFONT*/, hFont, true)
// Заполнение листбокса значениями
for (var i = 0; i < oPopup.aItems.length; i++)
AkelPad.SendMessage(oPopup.hLB, 0x0180/*LB_ADDSTRING*/, 0, oPopup.aItems[i])
// Выделяем первый элемент по умолчанию
// AkelPad.SendMessage(oPopup.hLB, 0x018E/*LB_SETCURSEL*/, 0, 0)
// oSys.Call("User32::InvalidateRect", oPopup.hLB, 0, true)
oSys.Call("User32::PostMessageW", oPopup.hLB, 0x0100/*WM_KEYDOWN*/, 40/*VK_DOWN*/, 0)
// Запускаем субклассирование редактора для того, чтобы перенаправлять VK_DOWN, VK_UP, VK_RETURN, VK_ESCAPE в попап
hWndEditSubClass = AkelPad.WindowSubClass(hWndEdit, EditCallback, 0x0100/*WM_KEYDOWN*/, 0x0101/*WM_KEYUP*/, 0x0202/*WM_LBUTTONUP*/) //
return 0
// case 0x8000: // WM_APP // выделение первого пункта в LB
// AkelPad.SendMessage(oPopup.hLB, 0x018E, 0, 0) // LB_SETCURSEL(0)
// oSys.Call("User32::InvalidateRect", oPopup.hLB, 0, true)
// return 0
case 5: // WM_SIZE
// Растягиваем ListBox при изменении размера попапа
var cx = lParam & 0xFFFF
var cy = (lParam >> 16) & 0xFFFF
if (oPopup.hLB)
oSys.Call("User32::MoveWindow", oPopup.hLB, 2, 2, cx - 4, cy - 4, true)
return 0
// case 0x002B: // WM_DRAWITEM
// //var lpDIS = lParam; // указатель на DRAWITEMSTRUCT
// PrintLog('WM_DRAWITEM')
// if (!oDIS) {
// oDIS = DRAWITEMSTRUCTwrp(lParam)
// sRect = makeStrBuff(8) //16/2 (sizeOf(RECT))
// lpRect = StrPtr(sRect)
// oRect = RECTwrp(lpRect)
// // PrintLog('Инициализация данных DialogCallback')
// } else {
// oDIS.pStructSet(lParam)
// }
// if (oDIS.CtlID() == 1001) {
// try {
// var hDC = oDIS.hDC() //AkelPad.MemRead(_PtrAdd(lpDIS, _X64?24:16), 8); // hDC (на x64 8 байт)
//
// var nCurSel = AkelPad.SendMessage(oPopup.hLB, 0x0188, 0, 0); // LB_GETCURSEL
// // Выбрать цвет фона и текста
// var bkColor, textColor;
// if ((oDIS.itemState() & 0x0001) || (oDIS.itemID() == nCurSel)) { // ODS_SELECTED
// bkColor = oSys.Call("User32::GetSysColor", 13); // COLOR_HIGHLIGHT
// textColor = oSys.Call("User32::GetSysColor", 14); // COLOR_HIGHLIGHTTEXT
// } else {
// bkColor = oSys.Call("User32::GetSysColor", 5); // COLOR_WINDOW
// textColor = oSys.Call("User32::GetSysColor", 8); // COLOR_WINDOWTEXT
// } //PrintLog('bkColor textColor: ' + bkColor + ' ' + textColor) // вывод: 16777215 0
//
// // Заливка фона
// var hBrush = oSys.Call("Gdi32::CreateSolidBrush", bkColor)//PrintLog('hBrush = ' + hBrush) // вывод - число (хэндл)
// var lprcItem = oDIS.rcItemPtr()
// var ret = oSys.Call("User32::FillRect", hDC, lprcItem, hBrush)
// //PrintLog('FillRect() => ' + ret) // вывод: 1
// oSys.Call("Gdi32::DeleteObject", hBrush);
//
// // Рисование текста
// /*ret = */oSys.Call("Gdi32::SetBkMode", hDC, 1);// TRANSPARENT
// //PrintLog('SetBkMode() => ' + ret) // вывод 2 либо 1
// oSys.Call("Gdi32::SetTextColor", hDC, textColor)
//
// with(oDIS.rcItem()){
// oRect.leftSet(left())
// oRect.topSet(top())
// oRect.rightSet(right())
// oRect.bottomSet(bottom())
// }
// var sText = GetItemText(oPopup.hLB, oDIS.itemID()) // Получение текста элемента
// /*ret = */oSys.Call("User32::DrawTextW", hDC, StrPtr(sText), -1, lpRect, 0x0000 | 0x0008 | 0x0010); // DT_SINGLELINE | DT_VCENTER | DT_LEFT
// //PrintLog('DrawTextW() => ' + ret) // вывод 17
//
// return 1; // обработано
// } catch(e) {
// PrintLog('Ошибка в WM_DRAWITEM' + e.message)
// return 0
// }
// }
// break;
case WM_MOUSEACTIVATE: //
// Возвращаем MA_NOACTIVATE (3) → клик по попапу не активирует его, фокус остаётся в редакторе
return MA_NOACTIVATE
case WM_NCACTIVATE: // предотвращает изменение внешнего вида окна (например, заголовка) при попытке активации.
return 1 //TRUE
// case 7:
// oSys.Call("User32::SetFocus", hWndEdit)
case 273: // WM_COMMAND
var nID = wParam & 0xFFFF
var nCode = (wParam >> 16) & 0xFFFF
//PrintLog('WM_COMMAND: ' + nID + ' ' + nCode + ' ' + wParam)
if (nID == 1001 && nCode == 2){ // LBN_DBLCLK WScript.Echo((1874).toString(16))
DoInsertAndClose()
return 0
}
return 0
case 0x0100: // WM_KEYDOWN
try {
switch (wParam){
case 13: // VK_RETURN
//oSys.Call("User32::SetFocus", oPopup.hWnd)
//setTimeout(DoInsertAndClose, 200) //выполняем DoInsertAndClose с отсрочкой 200 мс
DoInsertAndClose()
return 0
case 27: // VK_ESCAPE
ClosePopup()
return 0
case 38: // Up
var nCur = AkelPad.SendMessage(oPopup.hLB, 0x0188, 0, 0);
if (nCur > 0) {
AkelPad.SendMessage(oPopup.hLB, 0x018E, nCur - 1, 0);
// Принудительно перерисовать listbox, чтобы обновить выделение
oSys.Call("User32::InvalidateRect", oPopup.hLB, 0, true);
}
return 0;
case 40: // Down
var nCur = AkelPad.SendMessage(oPopup.hLB, 0x0188, 0, 0);
var nCount = AkelPad.SendMessage(oPopup.hLB, 0x018B, 0, 0);
if (nCur < nCount - 1) {
AkelPad.SendMessage(oPopup.hLB, 0x018E, nCur + 1, 0);
oSys.Call("User32::InvalidateRect", oPopup.hLB, 0, true);
}
return 0;
}
// Навигация и скроллинг (передаём в ListBox)
if (/*wParam == 38 || wParam == 40 || */wParam == 33 || wParam == 34 || wParam == 9){
oSys.Call("User32::SendMessageW", oPopup.hLB, uMsg, wParam, lParam)
return 0
}
} catch(e) {
PrintLog('Ошибка в WM_KEYDOWN: ' + e.message)
}
return 0
case 0x020A: // WM_MOUSEWHEEL
oSys.Call("User32::SendMessageW", oPopup.hLB, uMsg, wParam, lParam)
return 0
case 0x0202: // WM_LBUTTONUP
var hChild = oSys.Call("User32::ChildWindowFromPointEx", hWnd, lParam & 0xFFFF, (lParam >> 16) & 0xFFFF, 2)
if (hChild != oPopup.hLB && hChild != 0){
ClosePopup()
return 0
}
return 0
// case 0x0008: // WM_KILLFOCUS
// if (lParam != oPopup.hLB) ClosePopup()
// return 0
case 16: // WM_CLOSE
oSys.Call("User32::DestroyWindow", hWnd)
return 0
case 2: // WM_DESTROY
oPopup.hWnd = 0
oPopup.hLB = 0
if (MessageLoopOwnFlag) oSys.Call("User32::PostQuitMessage", 0)
return 0
}
return 0
//}(hWnd, uMsg, wParam, lParam)
}
function ListBoxCallback(hWnd, uMsg, wParam, lParam){
switch(uMsg){
case 0x02B: // WM_DRAWITEM
}
}
function GetItemText(hLB, nItemID){
var nLen = AkelPad.SendMessage(hLB, 0x18A/*LB_GETTEXTLEN*/, nItemID, 0)
var sText = makeStrBuff(nLen)
var lpText = AkelPad.MemStrPtr(sText)
AkelPad.SendMessage(hLB, 0x0189/*LB_GETTEXT*/, nItemID, lpText) // LB_GETTEXT
return sText
}
function DoInsertAndClose(){
var nSel = AkelPad.SendMessage(oPopup.hLB, 0x0188/*LB_GETCURSEL*/, 0, 0) // LB_GETCURSEL
if (nSel == -1) return
var nLen = AkelPad.SendMessage(oPopup.hLB, 0x18A/*LB_GETTEXTLEN*/, nSel, 0)
if (nLen <= 0 || nLen > 32768) return
var sText = makeStrBuff(nLen)
var lpText = AkelPad.MemStrPtr(sText)
AkelPad.SendMessage(oPopup.hLB, 0x0189/*LB_GETTEXT*/, nSel, lpText) // LB_GETTEXT
ClosePopup()
//oSys.Call("User32::SetFocus", oPopup.hEdit)
AkelPad.ReplaceSel(sText)
}
function ClosePopup(){
AkelPad.WindowUnsubClass(hWndEdit) // удалит самый последний субкласс, а именно тот, который был создан в DialogCallback
if (oPopup.hWnd && oSys.Call("User32::IsWindow", oPopup.hWnd))
oSys.Call("User32::PostMessageW", oPopup.hWnd, 16/*WM_CLOSE*/, 0, 0)
}
function ResetContent(){
AkelPad.SendMessage(oPopup.hLB, 0x184/*LB_RESETCONTENT*/, 0, 0)
}
}
//---Вспомогательные функции---//
function LoWord(nParam) {
return (nParam & 0xFFFF)
}
//WScript.Echo(HiWord(263145))
function HiWord(nParam) {
return (nParam >> 16) & 0xFFFF
}
function GetCaretPos(hEdit){
var sPointBuf = makeStrBuff(4)
var lpPoint = sPointBuf.StrPtr()
return (GetCaretPos = function(hEdit){
if (!hEdit) hEdit = AkelPad.GetEditWnd()
AkelPad.SendMessage(hEdit, 0x00D6/*EM_POSFROMCHAR*/, 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)
}
/*typedef struct tagRECT {
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT, *PRECT, *NPRECT, *LPRECT;*/
function RECTwrp(pStruct, oStruct, fullInit){
var aOffsets = (_X64)?[16,4,8,12]:[16,4,8,12]
var aDataFields = ['left', 3,
'top', 3,
'right', 3,
'bottom', 3]
return (RECTwrp = function (pStruct, oStruct, fullInit){
return makeStructWrapper(pStruct, oStruct, fullInit, aOffsets, aDataFields)
})(pStruct, oStruct, fullInit)
}
/*typedef struct tagDRAWITEMSTRUCT {
UINT CtlType;
UINT CtlID;
UINT itemID;
UINT itemAction;
UINT itemState;
HWND hwndItem;
HDC hDC;
RECT rcItem;
ULONG_PTR itemData;
} DRAWITEMSTRUCT, *PDRAWITEMSTRUCT, *LPDRAWITEMSTRUCT;*/
function DRAWITEMSTRUCTwrp(pStruct, oStruct, fullInit){
var aOffsets = (_X64)?[64,4,8,12,16,24,32,40,56]:[48,4,8,12,16,20,24,28,44]
var aDataFields = ['CtlType', 3,
'CtlID', 3,
'itemID', 3,
'itemAction', 3,
'itemState', 3,
'hwndItem', 2,
'hDC', 2,
'rcItem', 6, RECTwrp,
'itemData', 2]
return (DRAWITEMSTRUCTwrp = function (pStruct, oStruct, fullInit){
return makeStructWrapper(pStruct, oStruct, fullInit, aOffsets, aDataFields)
})(pStruct, oStruct, fullInit)
}Code: Select all
function EditCallback(hWnd, uMsg, wParam, lParam){
if (uMsg == 0x0202/*WM_LBUTTONUP*/){ // если был клик в произвольной области окна редактора
AkelPad.WindowNextProc(hWndEditSubClass, hWnd, uMsg, wParam, lParam)
ClosePopup() // то закрываем попап
} else if (wParam == 13/*VK_RETURN*/ || wParam == 27/*VK_ESCAPE*/ || wParam == 38/*VK_UP*/ || wParam == 40/*VK_DOWN*/){
//PrintLog('hWndEditSubClass = ' + hWndEditSubClass)
oSys.Call("User32::PostMessageW", oPopup.hLB, uMsg, wParam, lParam)// перенаправляем сообщение в попап-листбокс
AkelPad.WindowNoNextProc(hWndEditSubClass) // Блокируем дальнейшую обработку (не помогает)
return 1 // обработано (не помогает)
} else {
return 0
}
return 0
}-
Offline
- Posts: 17
- Joined: Tue Feb 03, 2026 1:20 pm
Re: Свой список автозамены
Название дурацкое у темы. Вообще изначально я хотел сделать не "свой" список а скопировать оригинальный список из плагина Coder, что в общем-то у меня почти получилось, только загвоздка вышла, с перехватом Enter и Escape