Можно ли обнаружить клавишу Esc с помощью функции Ask?

Хотелось бы обнаружить клавишу esc для выхода из цикла forever в псевдокоде:

навсегда [ url: спросите "Url: " if (url = esc) [перерыв] ]

Это возможно?

2 ответа

Решение

Простого ответа нет, вы должны использовать собственный консольный порт для правильной обработки, вот часть, взятая из одного из моих старых проектов:

REBOL [title: "Console port"]

set 'ctx-console make object! [
    system/console/busy: none
    system/console/break: false
    buffer: make string! 512
    history: system/console/history
    prompt: "## " ;system/console/prompt
    spec-char: none
    port: none
    init: func[][
        port: open/binary [scheme: 'console]
        set 's-print get in system/words 'print
        set 's-prin  get in system/words 'prin
        set 'prin func[msg /err /inf /user user-data][
            ctx-console/clear-line
            s-prin reform msg
            ctx-console/print-line
        ]
        set 'print func[msg /err /inf /user user-data][
            prin rejoin [reform msg newline]
        ]
        s-prin prompt
    ]
    print-line: func[][
        s-prin rejoin [ prompt head buffer "^(1B)[" length? buffer "D"]
    ]
    clear-line: func[][
        s-prin rejoin [
            "^(1B)[" (
            (index? buffer) +
            (length? prompt) +
            (length? buffer))
            "D^(1B)[K"
        ]
    ]
    key-actions: make block! [
        #{08} [;BACK
            if 0 < length? head buffer [
                buffer: remove back buffer
                s-prin rejoin [
                    "^(back)^(1B)[K"
                    buffer
                    "^(1B)["
                    length? buffer "D"
                ]
            ]
        ]
        #{7E} [;HOME
            s-prin rejoin ["^(1B)[" (index? buffer) - 1 "D"]
            buffer: head buffer
        ]
        #{7F} [;DELETE
            buffer: remove buffer
            s-prin rejoin ["^(1B)[K" buffer "^(1B)[" length? buffer "D"]
        ]
        #{1B} [;ESCAPE
            spec-char: copy/part port 1
            either spec-char = #{1B} [
                print "ESCAPE"
                clear-line
                set 'print :s-print
                set 'prin  :s-prin
                system/console/break: true
                on-escape
            ][
                switch append spec-char copy/part port 1 [
                    #{5B41} [;ARROW UP
                        if not tail? history [
                            clear-line
                            clear head buffer
                            s-prin join prompt buffer: copy history/1
                            history: next history
                            buffer: tail buffer
                        ]
                    ]
                    #{5B42} [;ARROW DOWN
                        clear-line
                        buffer: head buffer
                        clear buffer
                        if all [
                            not error? try [history: back history]
                            not none? history/1
                        ] [
                            buffer: copy history/1
                        ]
                        s-prin join prompt buffer
                        buffer: tail buffer
                    ]
                    #{5B43} [;ARROW RIGHT
                        if not tail? buffer [
                            s-prin "^(1B)[C"
                            buffer: next buffer
                        ]
                    ]
                    #{5B44} [;ARROW LEFT
                        if 1 < index? buffer [
                            s-prin "^(1B)[D"
                            buffer: back buffer
                        ]
                    ]
                ]
            ]
        ]
    ]
    do-command: func[comm /local e][
        set/any 'e attempt compose [do (comm)]

        if all [
            not unset? 'e
            value? 'e
            not object? :e
            not port? :e
            not function? :e
        ][
            print head clear skip rejoin [system/console/result mold :e] 127
            if (length? mold :e) > 127 [
                print "...^/"
            ]
        ]
    ]
    on-enter: func[input-str /local e][
        print rejoin [system/console/prompt input-str]
        do-command input-str
    ]
    on-escape: func[][halt]
    process: func[/local ch c tmp spec-char err][
        ch: to-char pick port 1
        either (ch = newline) or (ch = #"^M") [;ENTER
            tmp: copy head buffer
            if empty? tmp [return none]
            history: head history
            if any [empty? history tmp <> first history ] [
                insert history tmp
            ]
            clear-line
            buffer: head buffer
            clear buffer
            print-line
            on-enter tmp
        ][
            switch/default to-binary ch key-actions [
                either tail? buffer [
                    s-prin ch ;either local-echo [ch]["*"]
                ][
                    s-prin rejoin ["^(1B)[@" ch]
                ]
                buffer: insert buffer ch
            ]
        ]
    ]
]
ctx-console/init

;and now do something with your own console:
wait-list: reduce [ctx-console/port]
forever [
    attempt [ready: wait/all wait-list]
    if ready [
        ctx-console/process
    ]
]

Возможно, вы захотите изменить функции ctx-console/on-escape и ctx-console/on-enter.

Как чисто консольное приложение, я уверен, что ответ - нет.

esc используется для отмены выполнения скрипта.

Вы можете отключить это использование Esc....

 system/console/break: false

.... а клавиша esc теперь ничего не делает.

Если вы переключитесь на REBOL/VIEW и будете рады использовать всплывающее текстовое поле запроса, а не консольную строку запроса, тогда вы сможете перехватить esc, используя insert-event-func.

Другие вопросы по тегам