/*
* © 2009 ROBO Design
* http://www.robodesign.ro
*
* $Date: 2009-04-21 14:42:13 +0300 $
*/
/**
* @author Mihai Şucan
* @fileOverview Extension for the paint application. Allows users to draw
* inside the paint application using the keyboard, without any pointing
* device.
*/
/**
* @class The MouseKeys action.
*
* @param {Painter} app Reference to the main paint application object.
*/
function PaintMouseKeys (app) {
var canvas = app.buffer.canvas,
mouse = app.mouse;
/**
* Holds the current mouse movement speed in pixels.
*
* @private
* @type Number
*/
var speed = 1;
/**
* Holds the current mouse movement acceleration, taken from the
* configuration.
*
* @private
* @type Number
* @see PainterConfig.mousekeys_accel The mouse keys acceleration setting.
*/
var accel = PainterConfig.mousekeys_accel;
if (!canvas || !canvas.parentNode) {
return false;
}
/**
* Holds a reference to the DOM element representing the pointer on top of the
* canvas element.
*
* @private
* @type Element
*/
var pointer = document.createElement('div');
if (!pointer) {
return false;
}
pointer.id = 'mousekeysPointer';
pointer.style.display = 'none';
canvas.parentNode.appendChild(pointer);
/**
* Track the virtual pointer coordinates, by updating the position of the
* pointer element. This allows the keyboard users to see where
* they moved the virtual pointer.
*
* @param {Event} ev The DOM Event object.
*/
function pointerMousemove (ev) {
if (typeof ev.x_ == 'undefined' || !ev.kobj_ || !ev.kobj_.action || ev.kobj_.action != 'mousekeys') {
if (pointer.style.display == 'block') {
pointer.style.display = 'none';
}
return;
}
pointer.style.top = ev.y_ + 'px';
pointer.style.left = ev.x_ + 'px';
};
/**
* Dispatch a synthetic event to the buffer canvas element.
*
* @private
* @param {String} type The mouse event type to dispatch.
* @param {Event} ev The original DOM Event object.
*/
function dispatch (type, ev) {
var ev_new = document.createEvent('MouseEvents');
ev_new.initMouseEvent(type,
ev.bubbles, ev.cancelable,
ev.view, 0,
0, 0,
0, 0,
ev.ctrlKey, ev.altKey,
ev.shiftKey, ev.metaKey,
0, ev.relatedTarget);
// Make sure the new coordinates are passed to the event handlers.
ev_new.x_ = mouse.x;
ev_new.y_ = mouse.y;
// Make sure the event handlers can check this is a synthetic event.
// This is needed by the pointerMousemove() function.
ev_new.keyCode_ = ev.keyCode_;
ev_new.key_ = ev.key_;
ev_new.kid_ = ev.kid_;
ev_new.kobj_ = ev.kobj_;
canvas.dispatchEvent(ev_new);
};
/**
* The keydown
event handler.
*
*
This method requires a DOM Event object which has the
* ev.kobj_ object reference from the keyboard shortcuts
* configuration. The kobj_ object must have the param
* property. Support for the "Toggle" parameter is implemented. This parameter
* essentially means that a mouse event will be generated, either
* mousedown
or mouseup
. By alternating these two
* events, this method allows the user to start and stop the drawing operation
* at any moment using the keyboard shortcut they have configured.
*
*
Irrespective of the key the user pressed, this method does always reset
* the speed and acceleration of the pointer movement.
*
* @param {Event} ev The DOM Event object.
*
* @returns {Boolean} True if the keyboard shortcut was recognized, or false
* if not.
*
* @see PainterConfig.keys The keyboard shortcuts configuration object.
*/
this.keydown = function (ev) {
speed = 1;
accel = PainterConfig.mousekeys_accel;
if (pointer.style.display == 'none') {
pointer.style.display = 'block';
pointer.style.top = mouse.y + 'px';
pointer.style.left = mouse.x + 'px';
}
if (!ev || !ev.kobj_ || ev.kobj_.param != 'Toggle') {
return false;
}
var type = mouse.buttonDown ? 'mouseup' : 'mousedown';
dispatch(type, ev);
return true;
};
/**
* The keypress
event handler.
*
*
This method requires a DOM Event object with a ev.kobj_ * object reference to the keyboard shortcut configuration. The keyboard * shortcut configuration object must have the param property. * *
This event handler implements support for the following param * values: "SouthWest", "South", "SouthEast", "West", "East", "NorthWest", * "North" and "NorthEast", All of these values indicate the movement * direction. This method generates synthetic movemove events based * on the direction desired, effectively emulating the use of a real pointing * device. * * @param {Event} ev The DOM Event object. * * @returns {Boolean} True if the keyboard shortcut was recognized, or false * if not. * * @see PainterConfig.keys The keyboard shortcuts configuration object. */ this.keypress = function (ev) { if (!ev || !ev.kobj_ || !ev.kobj_.param) { return false; } if (ev.shiftKey) { speed += speed * accel * 3; } else { speed += speed * accel; } var w = canvas.width, h = canvas.height, x = mouse.x, y = mouse.y, step = Math.ceil(speed); switch (ev.kobj_.param) { case 'SouthWest': x -= step; y += step; break; case 'South': y += step; break; case 'SouthEast': x += step; y += step; break; case 'West': x -= step; break; case 'East': x += step; break; case 'NorthWest': x -= step; y -= step; break; case 'North': y -= step; break; case 'NorthEast': x += step; y -= step; break; default: return false; } if (x < 0) { x = 0; } else if (x > w) { x = w; } if (y < 0) { y = 0; } else if (y > h) { y = h; } mouse.x = x; mouse.y = y; dispatch('mousemove', ev); return true; }; /** * Handles action removal. This will remove the pointer DOM element and the * canvas event listener. */ this.actionRemove = function () { canvas.parentNode.removeChild(pointer); canvas.removeEventListener('mousemove', pointerMousemove, false); }; canvas.addEventListener('mousemove', pointerMousemove, false); }; window.addEventListener('load', function () { // Add the MouseKeys action to the Painter instance. if (window.PainterInstance) { PainterInstance.actionAdd('mousekeys', PaintMouseKeys); } }, false); // vim:set spell spl=en fo=wan1croql tw=80 ts=2 sw=2 sts=2 sta et ai cin fenc=utf-8 ff=unix: