我尝试按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
信号。那我怎么能持续清理这个领域呢?
答案 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
事件。