Форум » [x]Harbour » SOLVED!!! -> TRAPANYKEY() и KEYSEND() или запись/воспроизведение клавиатурных макросов » Ответить

SOLVED!!! -> TRAPANYKEY() и KEYSEND() или запись/воспроизведение клавиатурных макросов

Sergy: Практически со всем разобрался и восстановил функционал. Осталось одно и достаточно важное дело: автоматизация рутинных операций. В Clipper это происходило при помощи функций TRAPANYKEY/KEYSEND Первая при нажатии на любую клавишу в любом месте программы (включая GET/DBEDIT/ACHOICE/INKEY и тп) вызывает указанную мною функцию и передает ей код нажатой кнопки. Пользовательская функция тихо сидит и собирает эти коды в буфер - "записывает" нажатия клавиш юзером. В случае, если нужно "воспроизвести" записанные нажатия на кнопки, вызывается KEYSEND() с этим буфером в качестве параметра. Просто и логично. --------------------------------- Встал вопрос - чем и как заменить этот функционал? Без него меня разорвут на части - делать множество рутинных операций без клавиатурных макросов чокнешься...

Ответов - 45, стр: 1 2 3 All

Sergy: SergKis, это возможно то что нужно - буду изучать. Вот что еще нарыл ночью: http://www.freevbcode.com/ShowCode.asp?ID=4042 [pre2]Private Function KeyDown(ByVal vKey As KeyCodeConstants) _ As Boolean KeyDown = GetAsyncKeyState(vKey) And &H8000 End Function 'DEMO USAGE Private Sub Timer1_Timer() If KeyDown(vbKeyF10) Then MsgBox "You pressed F10!" 'This msgbox will appear regardless of the active app. End Sub[/pre2] Как понимаю - по таймеру вызывается GetAsyncKeyState и проверяется - если нажата F10 - выводится окно. У наст такое-же можно сделать через LastKey(). Но посмотрю подобные API функции - наверняка можно будет что-то найти "рядом", подходящее по условию.

Dima: Sergy пишет: Вот что еще нарыл ночью Тогда до кучи https://groups.google.com/forum/#!topic/comp.lang.xharbour/e77vVVb1Kuc

Dima: Sergy Вопрос решил ?


Sergy: Dima пишет: Вопрос решил ? к сожалению, нет, но очень нужно. Пока из идей - в фоне сидит функция, которая мониторит клавиатуру по LastKey(). Если установлен флаг "запись" - складывает в буффер. Только как отличить два подряд нажатия одной клавиши... ???

SergKis: Sergy пишет:к сожалению, нет, но очень нужно посмотрите в harbour\doc\en\set.txt и harbour\test\setkeys.prg используя aKey := hb_SetKeySave() // сохранить рабочие hb_SetKeyArray( { 49, 50, 52, 53 }, {| x | QOut( hb_keyChar( x ) ) } ) //блок кода на все клавиши поставить для записи и работы вполне можно организовать запись всех нажатий hb_SetKeySave(aKey) // восстановить рабочие

SergKis: Sergy пишет:Только как отличить два подряд нажатия одной клавиши... ??? есть LastKey() и NextKey(), а также Ваш буфер куда складываете ...

Sergy: SergKis пишет: посмотрите в harbour\doc\en\set.txt и harbour\test\setkeys.prg используя aKey := hb_SetKeySave() // сохранить рабочие hb_SetKeyArray( { 49, 50, 52, 53 }, {| x | QOut( hb_keyChar( x ) ) } ) //блок кода на все клавиши поставить для записи и работы вполне можно организовать запись всех нажатий hb_SetKeySave(aKey) // восстановить рабочие Честно говоря, не очень понял метода... Как понимаю, hb_SetKeyArray() предназначена для "оптового" назначения блоков кода клавишам. а hb_SetKeySave() - для быстрого снятия/установки блоков кода группе клавиш. Если поставить блок кода на клавишу - он сможет ее перехватить. Но как эта кнопка доберется туда, куда она была предназначена ? В get поле, memoedit() и тп... есть LastKey() и NextKey(), а также Ваш буфер куда складываете ... При помощи LastKey() и планировал отслеживать нажатия. Вот вызвана функция "записи" по таймеру, скажем, каждые 0,2 сек. Она видит через LastKey() что нажата кнопка F1, складывает в буфер, возвращает управление назад. Следующий вызов через 0,2 сек - LastKey() опять показывает K_F1 - как понять, это предыдущее нажатие или юзер еще раз успел за это время нажать ? В хвосте буфера мы видим, что уже есть F1. NextKey() покажет что-нибудь только если в буфере клавиатуры есть необработанные кнопки. Как она сможет помочь, если юзер, допустим, нажал два раза F1 с интервалом в 2 секунды ?

SergKis: Sergy конечно, я не очень понимаю как работает задача и юзера. но включив запись, я понимаю должно писаться ВСЕ, что нажимается иначе это уже алгоритмизация процесса (If ... else ... endif), а второй раз нажатая right(buffer, 1) == chr(Lastkey()). а определить где находитесь procname(1/2/...) или для get-ов делаем arraykey свой, для memoedit свой, ну т.д.

Dima: Sergy Покажи нам если не секрет процедуру записи макроса и его воспроизведения с комментариями , возможно тогда у кого то мысли появятся. PS О Clipper грю

Sergy: Dima пишет: если не секрет В начале программы: SETKEY(K_CTRL_F10,{|x,y,z|DefMacro(x,y,z,"Ctrl+F10",17408)}) SETKEY(K_F10 ,{||PlayMacro()}) Далее: [pre2] FUNC DefMacro(x,y,z,cKeyName,nKeyPlay) LOCAL wide,sx,ps DEFAULT cKeyName TO "ту-же кнопку" wide:=MAXCOL()-2 IF EMPTY(macro_buf[2]) // начинаем запись ? SayString(0,0,PADC("Запись макро-команды, для заверш. нажмите "+cKeyName+".",wide),c_blink) macro_buf:={"" ,; // 1.здесь храним макрос, обнуляем "work",; // 2.состояние макроса, запись, работа... TRAPANYKEY("MacroRec"),; // 3.old обработч.всех кнопок (мало-ли...) nKeyPlay,; // 4.кнопка воспр.макро - для предупрежд. FALSE} // 5.состояние поллинга ELSE // удаляем из буфера завершающ. Ctrl+F10 macro_buf[1] := LEFT(macro_buf[1],LEN(macro_buf[1])-2) macro_buf[2] := "" // выкл. признак записи макро TRAPANYKEY(macro_buf[3]) // восст.перехватчик кнопок (если был) // выводим мессагу на экран sx:="Макро-команда "+IIF(LEN(macro_buf[1]) > 0,"записана.","ОТМЕНЕНА.") SayString(0,0,PADC(sx,wide),c_blink) INKEY(1.5) // чуть-чуть ждем. ShowMainHeader() // восстанавливаем верхн.часть экрана ENDI RETURN * ------------- * FUNC MacroIsRec() // запись макро выполняется ? RETURN !EMPTY(macro_buf[2]) // только когда не-пустой 2й элемент * ------------- * FUNC MacroClean() // очищаем буфер при смене юзера macro_buf := {"",""} RETURN * ------------------- * FUNC MacroRec(nKeyCode) IF (nKeyCode != macro_buf[4]) // запрещена кнопка воспр.макро macro_buf[1] += I2BIN(nKeyCode) // сохраняем кнопку в расширенном виде SayString(0,0,STR(LEN(macro_buf[1])/2,6),c_blink) KEYSEND(I2BIN(nKeyCode),TRUE) ELSE SayString(0,0," err!") ENDI RETURN #endif * ------------ * FUNC PlayMacro() IF EMPTY(macro_buf[2]) // не во время записи ? KEYSEND(macro_buf[1],TRUE) ENDI RETURN [/pre2]

SergKis: Sergy может в таком направлении: [pre2] STATIC cBuf := '' ... SetKey(-29, {|| MyTest() }) SetKey(254, {|| MyTest(.T.) }) cTest := 'aaaabbbbb ' nTest := 1234567.89 @ 2, 10 GET cTest @ 3, 10 GET nTest READ ... FUNC myTest( lReg ) LOCAL nKey IF empty(lReg) // start records cBuf := '' KEYBOARD chr(254) ELSE // records DO WHILE ( nKey := inkey(0) ) != -9 cBuf += chr(nKey) IF nKey > 31 KEYBOARD chr(nKey)+chr(254) RETURN ENDIF ENDDO ENDIF RETURN [/pre2]

Sergy: идея - ОФИГИТЕЛЬНАЯ и все работает. Ровно до тех пор, пока не возникнет потребность в спец. клавишах F1..F10, стрелки и тп... SergKis пишет: IF nKey > 31 Вот блин засада... если я правильно понимаю, Clipper с легкостью засовывал в буфер клавиатуры все спец. символы, включая K_CTRL_F4 и прочие... Пока разбираюсь с HB_KeyPut()...

SergKis: Sergy пишет:Вот блин засада... это код с S87, его конечно надо перевести на aBuf, aadd(aBuf, nKey) и hb_keyput ..., к своей ситуации

Sergy: Короче бился и так и эдак, получилось вот что: [pre2] В начале программы достаточно поставить MacroNew("setup") FUNC MacroNew( cCmd ) STATIC nBuf := {},; msg1 := "Начало записи макро, Ctrl+F10 для завершения.",; rec_on := FALSE LOCAL nKey IF (cCmd == "setup") // define keys SETKEY(K_CTRL_F10, {|| MacroNew("rec") }) SETKEY(254, {|| MacroNew("get") }) SETKEY(K_F10, {|| MacroNew("play") }) ELSEIF (cCmd == "rec") // start records IF !rec_on nBuf := { } rec_on := TRUE HB_KeyPut(254) SayString(0,0,PADC(msg1,MAXCOL()+1),c_blink) ELSE SayString(0,0,PADC(" Macro recorded ",MAXCOL()+1),c_blink) INKEY(1) // чуть-чуть ждем. rec_on := FALSE ShowMainHeader() // восстанавливаем верхн.часть экрана ENDIF ELSEIF (cCmd == "get") // records a symbol DO WHILE ( nKey := INKEY(0) ) # K_CTRL_F10 // -9 конец записи тут произойдет автоматом AADD(nBuf,nKey) SayString(0,0,PADC(NTRIM(LEN(nBuf))+" <"+NTRIM(nKey)+"> "+msg1,MAXCOL()+1),c_blink) HB_KeyPut({nKey,254}) RETURN ENDDO SayString(0,0,PADC(" Macro recorded ",MAXCOL()+1),c_blink) INKEY(1) // чуть-чуть ждем. rec_on := FALSE ShowMainHeader() // восстанавливаем верхн.часть экрана ELSEIF (cCmd == "play") // play macro IF !rec_on HB_KeyPut(nBuf) ENDI ELSEIF (cCmd == "check") // record on ? RETURN rec_on ENDIF RETURN [/pre2] Вроде заработало. Но не могу подружить с DBEDIT() - не работает вообще никак. Ничего не записывается. А он очень нужен... Любая команда наподобие CLEAR TYPEAHEAD, KEYBOARD ломает алгоритм полностью. У себя в коде вычистил. Возможно что-то внутри RTL осталось... Вот что нашел в ChangeLog.txt: [pre2]2012-11-23 17:14 UTC+0100 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) * harbour/contrib/xhb/xhbtedit.prg * harbour/contrib/hbmysql/tsqlbrw.prg * harbour/contrib/hbodbc/browodbc.prg % eliminated NextKey() calls ; TOFIX: BrowseODBC() just like dbEdit() ignore setKey() actions If key is pressed during stabilization faze. I think it's implementation problem not intentional decision and it should be fixed - there is nothing worse then application which ignores some keystrokes if user types to fast ;) I'd like to ask authors of above code to check it.[/pre2] Причем заметил, что если комбинацию записать в другом месте программы, а потом воспроизвести ее в DBEDIT - все работает.

Pasha: Извините, я не следил за обсуждением, у самого есть некоторые вопросы. Идея записи и воспроизведения клавиатурных макросов сама по себе неплохая. Реализовать ее можно следующим образом: Запись кодов клавиш: #include "hbgtinfo.ch" Static aKeys := {} // массив клавиш hb_gtInfo(HB_GTI_INKEYFILTER, {|nk| KeyRec(nk)}) Static func KeyRec(nk) AADD(aKeys, nk) Return nk Остановить запись: hb_gtInfo(HB_GTI_INKEYFILTER, nil) Воспроизвести можно той же функцией hb_KeyPut, которая в качестве параметра принимает и массив: hb_KeyPut(aKeys)

Sergy: Pasha пишет: hb_gtInfo(HB_GTI_INKEYFILTER, {|nk| KeyRec(nk)}) Методо работает ОТЛИЧНО. Во всех возможных режимах прогнал. Все воскресенье прошло впустую... Спасибо!!! Harbour - сила.

Marquis31: Как тут уже пробегало, с помощью hb_gtInfo( HB_GTI_INKEYFILTER, ...) можно подменить код клавиши, например [pre2] hb_gtInfo( HB_GTI_INKEYFILTER, { | nKey | SWITCH nKey CASE HB_K_F10 RETURN K_ESC ENDSWITCH RETURN nKey } ) [/pre2] а как бы сделать еще один "финт ушами" и вставить еще несколько "нажатий"?

Sergy: Marquis31 пишет: а как бы сделать еще один "финт ушами" и вставить еще несколько "нажатий"? KEYSEND() - вставляет сколько душе угодно.

Marquis31: Сейчас проверю, но есть у меня подозрение, что это "нажатие" вернется в тот же обработчик, заданный в hb_gtInfo(...

Sergy: Конечно вернется - можно даже не проверять. Иначе этот обработчик не работал-бы... Только ведь в нем не все кнопки должны быть заменены, а только те, что нужны.



полная версия страницы