changeset 1783:5bc4fbf9c0fe

New event records for key and mouse handlers
author Adam Chlipala <adam@chlipala.net>
date Sat, 21 Jul 2012 10:02:53 -0400
parents 61c7eb1d3867
children e6bc6bbd7a32
files doc/manual.tex lib/js/urweb.js lib/ur/basis.urs src/monoize.sml src/settings.sml tests/globalHandlers.ur tests/keyEvent.ur tests/mouseEvent.ur
diffstat 8 files changed, 111 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/doc/manual.tex	Wed Jul 18 17:29:13 2012 -0400
+++ b/doc/manual.tex	Sat Jul 21 10:02:53 2012 -0400
@@ -2068,13 +2068,13 @@
 There are also functions to register standard document-level event handlers.
 
 $$\begin{array}{l}
- \mt{val} \; \mt{onClick} : \mt{transaction} \; \mt{unit} \to \mt{transaction} \; \mt{unit} \\
- \mt{val} \; \mt{onDblclick} : \mt{transaction} \; \mt{unit} \to \mt{transaction} \; \mt{unit} \\
- \mt{val} \; \mt{onKeydown} : (\mt{int} \to \mt{transaction} \; \mt{unit}) \to \mt{transaction} \; \mt{unit} \\
- \mt{val} \; \mt{onKeypress} : (\mt{int} \to \mt{transaction} \; \mt{unit}) \to \mt{transaction} \; \mt{unit} \\
- \mt{val} \; \mt{onKeyup} : (\mt{int} \to \mt{transaction} \; \mt{unit}) \to \mt{transaction} \; \mt{unit} \\
- \mt{val} \; \mt{onMousedown} : \mt{transaction} \; \mt{unit} \to \mt{transaction} \; \mt{unit} \\
- \mt{val} \; \mt{onMouseup} : \mt{transaction} \; \mt{unit} \to \mt{transaction} \; \mt{unit}
+ \mt{val} \; \mt{onClick} : (\mt{mouseEvent} \to \mt{transaction} \; \mt{unit}) \to \mt{transaction} \; \mt{unit} \\
+ \mt{val} \; \mt{onDblclick} : (\mt{mouseEvent} \to \mt{transaction} \; \mt{unit}) \to \mt{transaction} \; \mt{unit} \\
+ \mt{val} \; \mt{onKeydown} : (\mt{keyEvent} \to \mt{transaction} \; \mt{unit}) \to \mt{transaction} \; \mt{unit} \\
+ \mt{val} \; \mt{onKeypress} : (\mt{keyEvent} \to \mt{transaction} \; \mt{unit}) \to \mt{transaction} \; \mt{unit} \\
+ \mt{val} \; \mt{onKeyup} : (\mt{keyEvent} \to \mt{transaction} \; \mt{unit}) \to \mt{transaction} \; \mt{unit} \\
+ \mt{val} \; \mt{onMousedown} : (\mt{mouseEvent} \to \mt{transaction} \; \mt{unit}) \to \mt{transaction} \; \mt{unit} \\
+ \mt{val} \; \mt{onMouseup} : (\mt{mouseEvent} \to \mt{transaction} \; \mt{unit}) \to \mt{transaction} \; \mt{unit}
 \end{array}$$
 
 Versions of standard JavaScript functions are provided that event handlers may call to mask default handling or prevent bubbling of events up to parent DOM nodes, respectively.
--- a/lib/js/urweb.js	Wed Jul 18 17:29:13 2012 -0400
+++ b/lib/js/urweb.js	Sat Jul 21 10:02:53 2012 -0400
@@ -441,22 +441,55 @@
     window.setTimeout(function () { runHandlers("Server", serverHandlers, s); }, 0);
 }
 
-// Key events
+// Key and mouse events
 
 var uw_event = null;
 
-function kc() {
-    return window.event ? event.keyCode : (uw_event ? uw_event.which : 0);
+function uw_getEvent() {
+    return window.event ? window.event : uw_event;
 }
 
+function firstGood(x, y) {
+    if (x == undefined || x == 0)
+        return y;
+    else
+        return x;
+}
+
+function uw_mouseEvent() {
+    var ev = uw_getEvent();
+
+    return {_ScreenX : firstGood(ev.screenX, 0),
+            _ScreenY : firstGood(ev.screenY, 0),
+            _ClientX : firstGood(ev.clientX, 0),
+            _ClientY : firstGood(ev.clientY, 0),
+            _CtrlKey : firstGood(ev.ctrlKey, false),
+            _ShiftKey : firstGood(ev.shiftKey, false),
+            _AltKey : firstGood(ev.altKey, false),
+            _MetaKey : firstGood(ev.metaKey, false),
+            _Button : ev.button == 2 ? "Right" : ev.button == 1 ? "Middle" : "Left"};
+}
+
+function uw_keyEvent() {
+    var ev = uw_getEvent();
+
+    return {_KeyCode : firstGood(ev.keyCode, ev.which),
+            _CtrlKey : firstGood(ev.ctrlKey, false),
+            _ShiftKey : firstGood(ev.shiftKey, false),
+            _AltKey : firstGood(ev.altKey, false),
+            _MetaKey : firstGood(ev.metaKey, false)};
+}
+
+
+
 // Document events
 
 function uw_handler(name, f) {
     var old = document[name];
     if (old == undefined)
-        document[name] = function(event) { uw_event = event; execF(f); };
+        document[name] = function(event) { uw_event = event; execF(execF(f, uw_mouseEvent())); };
     else
-        document[name] = function(event) { uw_event = event; old(); execF(f); };
+        document[name] = function(event) { uw_event = event; old(); execF(execF(f, uw_mouseEvent())); };
 }
 
 function uw_onClick(f) {
@@ -478,9 +511,9 @@
 function uw_keyHandler(name, f) {
     var old = document[name];
     if (old == undefined)
-        document[name] = function(event) { uw_event = event; execF(execF(f, kc())); };
+        document[name] = function(event) { uw_event = event; execF(execF(f, uw_keyEvent())); };
     else
-        document[name] = function(event) { uw_event = event; old(); execF(execF(f, kc())); };
+        document[name] = function(event) { uw_event = event; old(); execF(execF(f, uw_keyEvent())); };
 }
 
 function uw_onKeydown(f) {
--- a/lib/ur/basis.urs	Wed Jul 18 17:29:13 2012 -0400
+++ b/lib/ur/basis.urs	Sat Jul 21 10:02:53 2012 -0400
@@ -784,12 +784,22 @@
 val br : bodyTagStandalone [Id = id]
 
 con focusEvents = [Onblur = transaction unit, Onfocus = transaction unit]
-con mouseEvents = [Onclick = transaction unit, Ondblclick = transaction unit,
-                   Onmousedown = transaction unit, Onmousemove = transaction unit,
-                   Onmouseout = transaction unit, Onmouseover = transaction unit,
-                   Onmouseup = transaction unit]
-con keyEvents = [Onkeydown = int -> transaction unit, Onkeypress = int -> transaction unit,
-                 Onkeyup = int -> transaction unit]
+
+datatype mouseButton = Left | Right | Middle
+
+type mouseEvent = { ScreenX : int, ScreenY : int, ClientX : int, ClientY : int,
+                    CtrlKey : bool, ShiftKey : bool, AltKey : bool, MetaKey : bool,
+                    Button : mouseButton }
+
+con mouseEvents = map (fn _ :: Unit => mouseEvent -> transaction unit)
+                          [Onclick, Ondblclick, Onmousedown, Onmousemove, Onmouseout, Onmouseover, Onmouseup]
+
+type keyEvent = { KeyCode : int,
+                  CtrlKey : bool, ShiftKey : bool, AltKey : bool, MetaKey : bool }
+
+con keyEvents = map (fn _ :: Unit => keyEvent -> transaction unit)
+                        [Onkeydown, Onkeypress, Onkeyup]
+
 (* Key arguments are character codes. *)
 con resizeEvents = [Onresize = transaction unit]
 con scrollEvents = [Onscroll = transaction unit]
@@ -955,13 +965,13 @@
 val onServerError : (string -> transaction unit) -> transaction unit
 
 (* More standard document-level JavaScript handlers *)
-val onClick : transaction unit -> transaction unit
-val onDblclick : transaction unit -> transaction unit
-val onKeydown : (int -> transaction unit) -> transaction unit
-val onKeypress : (int -> transaction unit) -> transaction unit
-val onKeyup : (int -> transaction unit) -> transaction unit
-val onMousedown : transaction unit -> transaction unit
-val onMouseup : transaction unit -> transaction unit
+val onClick : (mouseEvent -> transaction unit) -> transaction unit
+val onDblclick : (mouseEvent -> transaction unit) -> transaction unit
+val onKeydown : (keyEvent -> transaction unit) -> transaction unit
+val onKeypress : (keyEvent -> transaction unit) -> transaction unit
+val onKeyup : (keyEvent -> transaction unit) -> transaction unit
+val onMousedown : (mouseEvent -> transaction unit) -> transaction unit
+val onMouseup : (mouseEvent -> transaction unit) -> transaction unit
 
 (* Prevents default handling of current event *)
 val preventDefault : transaction unit
--- a/src/monoize.sml	Wed Jul 18 17:29:13 2012 -0400
+++ b/src/monoize.sml	Sat Jul 21 10:02:53 2012 -0400
@@ -3311,8 +3311,14 @@
                                                         val e =
                                                             case #1 dom of
                                                                 L'.TRecord [] => (L'.EApp (e, (L'.ERecord [], loc)), loc)
-                                                              | _ => (L'.EApp ((L'.EApp (e, (L'.EFfiApp ("Basis", "kc", []), loc)),
-                                                                                 loc), (L'.ERecord [], loc)), loc)
+                                                              | _ =>
+                                                                if String.isPrefix "Onkey" x then
+                                                                    (L'.EApp ((L'.EApp (e, (L'.EFfiApp ("Basis", "keyEvent", []), loc)),
+                                                                               loc), (L'.ERecord [], loc)), loc)
+                                                                else
+                                                                    (L'.EApp ((L'.EApp (e, (L'.EFfiApp ("Basis", "mouseEvent", []), loc)),
+                                                                               loc), (L'.ERecord [], loc)), loc)
+
                                                         val s' = " " ^ lowercaseFirst x ^ "='uw_event=event;exec("
                                                     in
                                                         ((L'.EStrcat (s,
--- a/src/settings.sml	Wed Jul 18 17:29:13 2012 -0400
+++ b/src/settings.sml	Sat Jul 21 10:02:53 2012 -0400
@@ -160,7 +160,8 @@
                         "onConnectFail",
                         "onDisconnect",
                         "onServerError",
-                        "kc",
+                        "mouseEvent",
+                        "keyEvent",
                         "debug",
                         "rand",
                         "now",
@@ -194,7 +195,8 @@
                         "onConnectFail",
                         "onDisconnect",
                         "onServerError",
-                        "kc",
+                        "mouseEvent",
+                        "keyEvent",
                         "onClick",
                         "onDblclick",
                         "onKeydown",
@@ -267,7 +269,8 @@
                           ("substring", "ssub"),
                           ("strcspn", "sspn"),
                           ("strlenGe", "strlenGe"),
-                          ("kc", "kc"),
+                          ("mouseEvent", "uw_mouseEvent"),
+                          ("keyEvent", "uw_keyEvent"),
                           ("minTime", "0"),
 
                           ("islower", "isLower"),
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/globalHandlers.ur	Sat Jul 21 10:02:53 2012 -0400
@@ -0,0 +1,4 @@
+fun main () : transaction page = return <xml>
+  <body onload={onDblclick (fn ev => alert ("ScreenX = " ^ show ev.ScreenX ^ "\nShiftKey = " ^ show ev.ShiftKey));
+                onKeypress (fn ev => alert ("KeyCode = " ^ show ev.KeyCode ^ "\nShiftKey = " ^ show ev.ShiftKey))}/>
+</xml>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/keyEvent.ur	Sat Jul 21 10:02:53 2012 -0400
@@ -0,0 +1,7 @@
+fun main () : transaction page = return <xml><body>
+  <ctextbox onkeypress={fn ev => alert ("KeyCode = " ^ show ev.KeyCode
+                                        ^ "\nCtrlKey = " ^ show ev.CtrlKey
+                                        ^ "\nShiftKey = " ^ show ev.ShiftKey
+                                        ^ "\nAltKey = " ^ show ev.AltKey
+                                        ^ "\nMetaKey = " ^ show ev.MetaKey)}/>
+</body></xml>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/mouseEvent.ur	Sat Jul 21 10:02:53 2012 -0400
@@ -0,0 +1,16 @@
+val show_mouseButton = mkShow (fn b => case b of
+                                           Left => "Left"
+                                         | Middle => "Middle"
+                                         | Right => "Right")
+
+fun main () : transaction page = return <xml><body>
+  <button onclick={fn ev => alert ("ScreenX = " ^ show ev.ScreenX
+                                   ^ "\nScreenY = " ^ show ev.ScreenY
+                                   ^ "\nClientX = " ^ show ev.ClientX
+                                   ^ "\nClientY = " ^ show ev.ClientY
+                                   ^ "\nCtrlKey = " ^ show ev.CtrlKey
+                                   ^ "\nShiftKey = " ^ show ev.ShiftKey
+                                   ^ "\nAltKey = " ^ show ev.AltKey
+                                   ^ "\nMetaKey = " ^ show ev.MetaKey
+                                   ^ "\nButton = " ^ show ev.Button)}/>
+</body></xml>