1 /* 2 * © 2009 ROBO Design 3 * http://www.robodesign.ro 4 * 5 * $Date: 2009-04-21 14:42:13 +0300 $ 6 */ 7 8 /** 9 * @author <a lang="ro" href="http://www.robodesign.ro/mihai">Mihai Şucan</a> 10 * @fileOverview Extension for the paint application. Allows users to draw 11 * inside the paint application using the keyboard, without any pointing 12 * device. 13 */ 14 15 16 /** 17 * @class The MouseKeys action. 18 * 19 * @param {Painter} app Reference to the main paint application object. 20 */ 21 function PaintMouseKeys (app) { 22 var canvas = app.buffer.canvas, 23 mouse = app.mouse; 24 25 /** 26 * Holds the current mouse movement speed in pixels. 27 * 28 * @private 29 * @type Number 30 */ 31 var speed = 1; 32 33 /** 34 * Holds the current mouse movement acceleration, taken from the 35 * configuration. 36 * 37 * @private 38 * @type Number 39 * @see PainterConfig.mousekeys_accel The mouse keys acceleration setting. 40 */ 41 var accel = PainterConfig.mousekeys_accel; 42 43 if (!canvas || !canvas.parentNode) { 44 return false; 45 } 46 47 /** 48 * Holds a reference to the DOM element representing the pointer on top of the 49 * canvas element. 50 * 51 * @private 52 * @type Element 53 */ 54 var pointer = document.createElement('div'); 55 if (!pointer) { 56 return false; 57 } 58 pointer.id = 'mousekeysPointer'; 59 pointer.style.display = 'none'; 60 canvas.parentNode.appendChild(pointer); 61 62 /** 63 * Track the virtual pointer coordinates, by updating the position of the 64 * <var>pointer</var> element. This allows the keyboard users to see where 65 * they moved the virtual pointer. 66 * 67 * @param {Event} ev The DOM Event object. 68 */ 69 function pointerMousemove (ev) { 70 if (typeof ev.x_ == 'undefined' || !ev.kobj_ || !ev.kobj_.action || ev.kobj_.action != 'mousekeys') { 71 if (pointer.style.display == 'block') { 72 pointer.style.display = 'none'; 73 } 74 return; 75 } 76 77 pointer.style.top = ev.y_ + 'px'; 78 pointer.style.left = ev.x_ + 'px'; 79 }; 80 81 /** 82 * Dispatch a synthetic event to the buffer canvas element. 83 * 84 * @private 85 * @param {String} type The mouse event type to dispatch. 86 * @param {Event} ev The original DOM Event object. 87 */ 88 function dispatch (type, ev) { 89 var ev_new = document.createEvent('MouseEvents'); 90 91 ev_new.initMouseEvent(type, 92 ev.bubbles, ev.cancelable, 93 ev.view, 0, 94 0, 0, 95 0, 0, 96 ev.ctrlKey, ev.altKey, 97 ev.shiftKey, ev.metaKey, 98 0, ev.relatedTarget); 99 100 // Make sure the new coordinates are passed to the event handlers. 101 ev_new.x_ = mouse.x; 102 ev_new.y_ = mouse.y; 103 104 // Make sure the event handlers can check this is a synthetic event. 105 // This is needed by the pointerMousemove() function. 106 ev_new.keyCode_ = ev.keyCode_; 107 ev_new.key_ = ev.key_; 108 ev_new.kid_ = ev.kid_; 109 ev_new.kobj_ = ev.kobj_; 110 111 canvas.dispatchEvent(ev_new); 112 }; 113 114 /** 115 * The <code>keydown</code> event handler. 116 * 117 * <p>This method requires a DOM Event object which has the 118 * <var>ev.kobj_</var> object reference from the keyboard shortcuts 119 * configuration. The <var>kobj_</var> object must have the <var>param</var> 120 * property. Support for the "Toggle" parameter is implemented. This parameter 121 * essentially means that a mouse event will be generated, either 122 * <code>mousedown</code> or <code>mouseup</code>. By alternating these two 123 * events, this method allows the user to start and stop the drawing operation 124 * at any moment using the keyboard shortcut they have configured. 125 * 126 * <p>Irrespective of the key the user pressed, this method does always reset 127 * the speed and acceleration of the pointer movement. 128 * 129 * @param {Event} ev The DOM Event object. 130 * 131 * @returns {Boolean} True if the keyboard shortcut was recognized, or false 132 * if not. 133 * 134 * @see PainterConfig.keys The keyboard shortcuts configuration object. 135 */ 136 this.keydown = function (ev) { 137 speed = 1; 138 accel = PainterConfig.mousekeys_accel; 139 140 if (pointer.style.display == 'none') { 141 pointer.style.display = 'block'; 142 pointer.style.top = mouse.y + 'px'; 143 pointer.style.left = mouse.x + 'px'; 144 } 145 146 if (!ev || !ev.kobj_ || ev.kobj_.param != 'Toggle') { 147 return false; 148 } 149 150 var type = mouse.buttonDown ? 'mouseup' : 'mousedown'; 151 dispatch(type, ev); 152 153 return true; 154 }; 155 156 /** 157 * The <code>keypress</code> event handler. 158 * 159 * <p>This method requires a DOM Event object with a <var>ev.kobj_</var> 160 * object reference to the keyboard shortcut configuration. The keyboard 161 * shortcut configuration object must have the <var>param</var> property. 162 * 163 * <p>This event handler implements support for the following <var>param</var> 164 * values: "SouthWest", "South", "SouthEast", "West", "East", "NorthWest", 165 * "North" and "NorthEast", All of these values indicate the movement 166 * direction. This method generates synthetic <var>movemove</var> events based 167 * on the direction desired, effectively emulating the use of a real pointing 168 * device. 169 * 170 * @param {Event} ev The DOM Event object. 171 * 172 * @returns {Boolean} True if the keyboard shortcut was recognized, or false 173 * if not. 174 * 175 * @see PainterConfig.keys The keyboard shortcuts configuration object. 176 */ 177 this.keypress = function (ev) { 178 if (!ev || !ev.kobj_ || !ev.kobj_.param) { 179 return false; 180 } 181 182 if (ev.shiftKey) { 183 speed += speed * accel * 3; 184 } else { 185 speed += speed * accel; 186 } 187 188 var w = canvas.width, 189 h = canvas.height, 190 x = mouse.x, 191 y = mouse.y, 192 step = Math.ceil(speed); 193 194 switch (ev.kobj_.param) { 195 case 'SouthWest': 196 x -= step; 197 y += step; 198 break; 199 case 'South': 200 y += step; 201 break; 202 case 'SouthEast': 203 x += step; 204 y += step; 205 break; 206 case 'West': 207 x -= step; 208 break; 209 case 'East': 210 x += step; 211 break; 212 case 'NorthWest': 213 x -= step; 214 y -= step; 215 break; 216 case 'North': 217 y -= step; 218 break; 219 case 'NorthEast': 220 x += step; 221 y -= step; 222 break; 223 default: 224 return false; 225 } 226 227 if (x < 0) { 228 x = 0; 229 } else if (x > w) { 230 x = w; 231 } 232 233 if (y < 0) { 234 y = 0; 235 } else if (y > h) { 236 y = h; 237 } 238 239 mouse.x = x; 240 mouse.y = y; 241 242 dispatch('mousemove', ev); 243 244 return true; 245 }; 246 247 /** 248 * Handles action removal. This will remove the pointer DOM element and the 249 * canvas event listener. 250 */ 251 this.actionRemove = function () { 252 canvas.parentNode.removeChild(pointer); 253 canvas.removeEventListener('mousemove', pointerMousemove, false); 254 }; 255 256 canvas.addEventListener('mousemove', pointerMousemove, false); 257 }; 258 259 window.addEventListener('load', function () { 260 // Add the MouseKeys action to the Painter instance. 261 if (window.PainterInstance) { 262 PainterInstance.actionAdd('mousekeys', PaintMouseKeys); 263 } 264 }, false); 265 266 // vim:set spell spl=en fo=wan1croql tw=80 ts=2 sw=2 sts=2 sta et ai cin fenc=utf-8 ff=unix: 267