键盘信号和折叠在榆

时间:2015-05-14 17:06:08

标签: elm

我尝试按Enter键创建一个提交输入的文本字段,并由Escape清除。

import Graphics.Element exposing (flow, down, show)
import Signal exposing ((<~), (~))
import Graphics.Input.Field exposing (noContent, defaultStyle, field)
import String
import Keyboard

main = Signal.map view (Signal.foldp step init signals)

signals = (,,) <~ box.signal
                ~ Signal.sampleOn Keyboard.enter box.signal
                ~ escape

escape = Keyboard.isDown 27

box = Signal.mailbox noContent

init = (noContent, noContent, False)

view (text, query, clear) =
    flow down
        [ field defaultStyle (Signal.message box.address) "Enter text" text
        , show (String.words query.string)
        ]

step (text, query, clear) _ =
    case clear of
        False -> (text, query, clear)
        True -> (noContent, noContent, clear)

仅在保持Escape时生成一个空字段,并恢复到Escape释放时输入的内容。

试图理解为什么会出现这种情况,这引出了一个较小的例子:

import Graphics.Element exposing (show)
import Signal
import Char
import String
import Keyboard

main = Signal.map show input

input = Signal.foldp step "" (Signal.map2 (,) Keyboard.presses escapeDown)

escapeDown = Keyboard.isDown 27

step (keyCode, esc) string =
    case esc of
        True -> ""
        False -> string ++ keyToString keyCode

keyToString = String.fromChar << Char.fromCode

在按Escape时清空累积的字符串,但释放它会产生一个字符串(最后输入的)字符。

根据我的理解,在持有和发布密钥时会触发Keyboard.isDown信号。那我怎么能持续清理这个领域呢?

1 个答案:

答案 0 :(得分:3)

您看到此行为的原因

当您从两个信号(Signal (KeyCode,Bool) / Signal KeyCode)中创建成对信号(Signal Bool)时,每次信号更新时,该对信号都会更新。因此Signal.map2 (,) Keyboard.presses escapeDown随着时间的推移可能是:

(0,False), (97,False), (98,False), (98,True), (98,False)
^          ^ press 'a' ^ press 'b'  ^          ^ release escape
program start                       press escape

当你按下escape时,这对值会发生变化,foldp会更新为空字符串。当您释放escape时,这对值会再次更改,因此foldp会再次更新,找到False值,因此将您按下的最后一个字符追加到空字符串中。

解决方案

在这种情况下,你真的对按下转义时的事件感兴趣,而不是在它isDown时感兴趣。在这种情况下,不是创建一对信号,而是merge信号更好。为此,他们需要属于同一类型。这是一个例子:

import Graphics.Element exposing (show)
import Signal exposing ((<~))
import Char
import String
import Keyboard

type Input = KeyPress Keyboard.KeyCode | EscapePress

main = Signal.map show output

presses = KeyPress <~ Signal.filter ((/=) 27) 0 Keyboard.presses
escapePress = always EscapePress <~ escapeDown
input = Signal.merge escapePress presses

output = Signal.foldp step "" input

escapeDown = Keyboard.isDown 27

step input string =
    case input of
        EscapePress -> ""
        KeyPress keyCode -> string ++ keyToString keyCode

keyToString = String.fromChar << Char.fromCode

使用联合类型Input,我们代表程序的不同输入。压力机包装在联合类型的KeyPress构造函数中。转义按钮由其他构造函数EscapePress表示。现在您有两个相同类型的信号,您可以merge。在step函数中,您可以在Input的构造函数上进行模式匹配,并处理熟悉的案例。
请注意,我正在过滤Keyboard.presses信号,因此您无法通过按下,按住或释放转义键来获得KeyPress事件。