@@ -17,27 +17,36 @@ Elm.Native.Keyboard.make = function(elm) {
17 var NList = Elm.Native.List.make(elm);
17 var NList = Elm.Native.List.make(elm);
18 var Utils = Elm.Native.Utils.make(elm);
18 var Utils = Elm.Native.Utils.make(elm);
20− var downEvents = Signal.constant(0);
20+ var downEvents = Signal.constant(null);
21− var upEvents = Signal.constant(0);
21+ var upEvents = Signal.constant(null);
22− var blurEvents = Signal.constant(0);
22+ var blurEvents = Signal.constant(null);
24 elm.addListener([downEvents.id], document, 'keydown', function down(e) {
24 elm.addListener([downEvents.id], document, 'keydown', function down(e) {
25− elm.notify(downEvents.id, e.keyCode);
25+ elm.notify(downEvents.id, e);
28 elm.addListener([upEvents.id], document, 'keyup', function up(e) {
28 elm.addListener([upEvents.id], document, 'keyup', function up(e) {
29− elm.notify(upEvents.id, e.keyCode);
29+ elm.notify(upEvents.id, e);
32 elm.addListener([blurEvents.id], document, 'blur', function blur(e) {
32 elm.addListener([blurEvents.id], document, 'blur', function blur(e) {
33− elm.notify(blurEvents.id, NList.Nil);
33+ elm.notify(blurEvents.id, null);
36+ function state(alt, meta, keyCodes) {
43+ var emptyState = state(false, false, NList.Nil);
36 function KeyMerge(down, up, blur) {
45 function KeyMerge(down, up, blur) {
37 var args = [down,up,blur];
46 var args = [down,up,blur];
38 this.id = Utils.guid();
47 this.id = Utils.guid();
39 // Ignore starting values here
48 // Ignore starting values here
40− this.value = NList.Nil
49+ this.value = emptyState;
41 this.kids = [];
50 this.kids = [];
43 var n = args.length;
52 var n = args.length;
@@ -48,18 +57,22 @@ Elm.Native.Keyboard.make = function(elm) {
49 if (changed) {
58 if (changed) {
50 // We know this a change must only be one of the following cases
59 // We know this a change must only be one of the following cases
51− if (parentID === down.id && !A2(NList.member, down.value, this.value)) {
60+ if (parentID === down.id && !A2(NList.member, down.value.keyCode, this.value.keyCodes)) {
52 isChanged = true;
61 isChanged = true;
53− this.value = NList.Cons(down.value, this.value);
63+ var newCodes = NList.Cons(v.keyCode, this.value.keyCodes);
64+ this.value = state(v.altKey, v.metaKey, newCodes);
55 else if (parentID === up.id) {
66 else if (parentID === up.id) {
56 isChanged = true;
67 isChanged = true;
57− var notEq = function(kc) { return kc !== up.value };
69+ var notEq = function(kc) { return kc !== v.keyCode };
58− this.value = A2(NList.filter, notEq, this.value);
70+ var newCodes = A2(NList.filter, notEq, this.value.keyCodes);
71+ this.value = state(v.altKey, v.metaKey, newCodes);
60 else if (parentID === blur.id) {
73 else if (parentID === blur.id) {
61 isChanged = true;
74 isChanged = true;
62− this.value = NList.Nil;
75+ this.value = emptyState;
65 if (count == n) {
78 if (count == n) {
@@ -71,45 +84,65 @@ Elm.Native.Keyboard.make = function(elm) {
72 for (var i = n; i--; ) {
85 for (var i = n; i--; ) {
73 args[i].kids.push(this);
86 args[i].kids.push(this);
87+ args[i].defaultNumberOfKids += 1;
77− var keysDown = Signal.dropRepeats(new KeyMerge(downEvents,upEvents,blurEvents));
91+ var keyMerge = new KeyMerge(downEvents,upEvents,blurEvents);
93+ // select a part of a keyMerge and dropRepeats the result
79 function keySignal(f) {
94 function keySignal(f) {
80− var signal = A2(Signal.lift, f, keysDown);
95+ var signal = A2(Signal.lift, f, keyMerge);
81 // must set the default number of kids to make it possible to filter
96 // must set the default number of kids to make it possible to filter
82 // these signals if they are not actually used.
97 // these signals if they are not actually used.
83− keysDown.defaultNumberOfKids += 1;
98+ keyMerge.defaultNumberOfKids += 1;
84 signal.defaultNumberOfKids = 1;
99 signal.defaultNumberOfKids = 1;
85− var filtered = Signal.dropRepeats(signal)
100+ var filtered = Signal.dropRepeats(signal);
86 filtered.defaultNumberOfKids = 0;
101 filtered.defaultNumberOfKids = 0;
87 return filtered;
102 return filtered;
105+ // break keyMerge into parts
106+ var keysDown = keySignal(function getKeyCodes(v) {
109+ var alt = keySignal(function getKeyCodes(v) {
112+ var meta = keySignal(function getKeyCodes(v) {
90 function dir(up, down, left, right) {
116 function dir(up, down, left, right) {
91− function f(ks) {
117+ function toDirections(state) {
118+ var keyCodes = state.keyCodes;
92 var x = 0, y = 0;
119 var x = 0, y = 0;
93− while (ks.ctor === "::") {
120+ while (keyCodes.ctor === "::") {
94− switch (ks._0) {
121+ switch (keyCodes._0) {
95 case left : --x; break;
122 case left : --x; break;
96 case right: ++x; break;
123 case right: ++x; break;
97 case up : ++y; break;
124 case up : ++y; break;
98 case down : --y; break;
125 case down : --y; break;
100− ks = ks._1;
127+ keyCodes = keyCodes._1;
102 return { _:{}, x:x, y:y };
129 return { _:{}, x:x, y:y };
104− return keySignal(f);
131+ return keySignal(toDirections);
107− function is(key) { return keySignal(NList.member(key)); }
134+ function is(key) {
135+ return keySignal(function(v) {
136+ return A2( NList.member, key, v.keyCodes );
109 var lastPressed = downEvents;
140 var lastPressed = downEvents;
111 return elm.Native.Keyboard.values = {
142 return elm.Native.Keyboard.values = {
112 isDown:is,
143 isDown:is,
113 directions:F4(dir),
146 directions:F4(dir),
114 keysDown:keysDown,
147 keysDown:keysDown,
115 lastPressed:lastPressed
148 lastPressed:lastPressed