2015-05-14 63 views
2

我正在嘗試通過按Enter鍵提交其輸入的文本字段並通過Escape清除。鍵盤信號和在Elm摺疊

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 

字符的累積串被清空上按下Esc鍵,但其釋放導致單一的字符串(最後進入)字符。

據我所知,Keyboard.isDown信號在按住鍵和釋放鍵時被觸發。那麼我怎樣才能持久地清理這個領域呢?

回答

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 

當您按下逃生,一對價值的變化,你的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,我們代表的是不同的輸入到程序。印刷機被包裝在union類型的KeyPress構造函數中。退出按鈕由其他構造函數EscapePress表示。現在您有兩個相同類型的信號,您可以使用merge。在您的step函數中,您的的構造函數的模式匹配,並處理熟悉的情況。
請注意,我正在過濾Keyboard.presses信號,因此按下或放開退出鍵時不會收到KeyPress事件。