Elm 中的键盘信号和 foldp
Keyboard signals and foldp in 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
信号在按住和释放键时触发。那么如何才能持久清场呢?
您看到此行为的原因
当您从两个信号 (Signal KeyCode
/Signal Bool
) 中创建成对信号 (Signal (KeyCode,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
当您按下转义键时,这对值会发生变化,并且您的 foldp
会更新为空字符串。当您释放转义符时,这对值再次更改,因此 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
事件。
我正在尝试创建一个文本字段,该字段通过按 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
信号在按住和释放键时触发。那么如何才能持久清场呢?
您看到此行为的原因
当您从两个信号 (Signal KeyCode
/Signal Bool
) 中创建成对信号 (Signal (KeyCode,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
当您按下转义键时,这对值会发生变化,并且您的 foldp
会更新为空字符串。当您释放转义符时,这对值再次更改,因此 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
事件。