I added support for key events. There is some extra code to direct the key events to the last selected "focused" widget, did not add tabbing yet. Since a canvas is not focusable in html 5.
Added support for most of the keycode in chrome and firefox (should also include IE), but tested it on chrome and firefox.
Added also charCode to it, although it does not take from the browser and is according default us keyboard.
Test the keyCode and charCode on both. The - in firefox is a keypad-. So shift- is not charcode _. Firefox under Ubuntu does not handle \' \^ \` \~ \" well because these are "escapee" characters.
Here is the code
//////////////////////////////////////////////////////////////////////////
// EventListeners
//////////////////////////////////////////////////////////////////////////
//Some elements are no focusable so then we create our focussing system
var focusWidget = null;
var keyDownHandler = function(e)
{
var walker = focusWidget
while(walker != null)
{
if(walker.m_keyDownListener != null)
{
walker.m_keyDownListener(e);
break;
}
walker = walker.parentNode;
}
}
var keyUpHandler = function(e)
{
var walker = focusWidget
while(walker != null)
{
if(walker.m_keyUpListener != null)
{
walker.m_keyUpListener(e);
break;
}
walker = walker.parentNode;
}
}
var mouseHandler = function(e)
{
focusWidget = e.target
}
this.document.addEventListener("keydown", keyDownHandler, false);
this.document.addEventListener("keyup", keyUpHandler, false);
this.document.addEventListener("mouseup", mouseHandler, true);
fan.fwt.WidgetPeer.prototype.attachEventListener = function(self, type, evtId, listeners)
{
var peer = this;
var funcMouse = function(e)
{
// find pos relative to widget
var dis = peer.posOnWindow(self);
var mx = e.clientX - dis.m_x;
var my = e.clientY - dis.m_y;
// make sure to rel against window root
var win = self.window();
if (win != null && win.peer.root != null)
{
mx -= win.peer.root.offsetLeft;
my -= win.peer.root.offsetTop;
}
// cache event type
var isClickEvent = evtId == fan.fwt.EventId.m_mouseDown ||
evtId == fan.fwt.EventId.m_mouseUp;
var isWheelEvent = evtId == fan.fwt.EventId.m_mouseWheel;
// create fwt::Event and invoke handler
var evt = fan.fwt.Event.make();
evt.m_id = evtId;
evt.m_pos = fan.gfx.Point.make(mx, my);
evt.m_widget = self;
evt.m_key = fan.fwt.WidgetPeer.toKey(e);
if(evt.m_key)
evt.m_keyChar = fan.fwt.WidgetPeer.keyToCharCode(evt.m_key)
if (isClickEvent)
{
evt.m_button = e.button + 1;
evt.m_count = fan.fwt.WidgetPeer.processMouseClicks(peer, evt);
}
if (isWheelEvent)
{
evt.m_button = 1; // always set to middle button?
evt.m_delta = fan.fwt.WidgetPeer.toWheelDelta(e);
}
// invoke handlers
var list = listeners.list();
for (var i=0; i<list.m_size; i++)
{
list.get(i).call(evt);
if (evt.m_consumed) break;
}
// prevent bubbling
e.stopPropagation();
return false;
}
// special handler for firefox
if (type == "mousewheel" && fan.fwt.DesktopPeer.$isFirefox) type = "DOMMouseScroll";
if (evtId == fan.fwt.EventId.m_keyDown)
{
this.elem.m_keyDownListener = funcMouse;
}
else if(evtId == fan.fwt.EventId.m_keyUp)
{
this.elem.m_keyUpListener = funcMouse;
}
else
{
// attach event handler
this.elem.addEventListener(type, funcMouse, false);
}
}
fan.fwt.WidgetPeer.processMouseClicks = function(peer, e)
{
// init mouse clicks if not defined
if (peer.mouseClicks == null)
{
peer.mouseClicks = {
last: new Date().getTime(),
pos: e.m_pos,
cur: 1
};
return peer.mouseClicks.cur;
}
// only process on mousedown
if (e.m_id != fan.fwt.EventId.m_mouseDown)
return peer.mouseClicks.cur;
// verify pos and frequency
var now = new Date().getTime();
var diff = now - peer.mouseClicks.last;
if (diff < 600 && peer.mouseClicks.pos.equals(e.m_pos))
{
// increment click count
peer.mouseClicks.cur++;
}
else
{
// reset handler
peer.mouseClicks.pos = e.m_pos;
peer.mouseClicks.cur = 1;
}
// update ts and return result
peer.mouseClicks.last = now;
return peer.mouseClicks.cur;
}
fan.fwt.WidgetPeer.toWheelDelta = function(e)
{
var wx = 0;
var wy = 0;
if (e.wheelDeltaX != null)
{
// WebKit
wx = -e.wheelDeltaX;
wy = -e.wheelDeltaY;
// Safari
if (wx % 120 == 0) wx = wx / 40;
if (wy % 120 == 0) wy = wy / 40;
}
else if (e.wheelDelta != null)
{
// IE
wy = -e.wheelDelta;
if (wy % 120 == 0) wy = wy / 40;
}
else if (e.detail != null)
{
// Firefox
wx = e.axis == 1 ? e.detail : 0;
wy = e.axis == 2 ? e.detail : 0;
}
// make sure we have ints and return
wx = wx > 0 ? Math.ceil(wx) : Math.floor(wx);
wy = wy > 0 ? Math.ceil(wy) : Math.floor(wy);
return fan.gfx.Point.make(wx, wy);
}
fan.fwt.WidgetPeer.toKey = function(event)
{
// find primary key
var key = null;
if (event.keyCode != null && event.keyCode > 0)
key = fan.fwt.WidgetPeer.keyCodeToKey(event.keyCode);
if (event.shiftKey) key = key==null ? fan.fwt.Key.m_shift : key.plus(fan.fwt.Key.m_shift);
if (event.altKey) key = key==null ? fan.fwt.Key.m_alt : key.plus(fan.fwt.Key.m_alt);
if (event.ctrlKey) key = key==null ? fan.fwt.Key.m_ctrl : key.plus(fan.fwt.Key.m_ctrl);
// TODO FIXIT
//if (event.commandKey) key = key.plus(Key.command);
return key;
}
fan.fwt.WidgetPeer.keyCodeToKey = function(keyCode)
{
//Codes for most common browsers taken from http://unixpapa.com/js/key.html
switch (keyCode)
{
case 38: return fan.fwt.Key.m_up;
case 40: return fan.fwt.Key.m_down;
case 37: return fan.fwt.Key.m_left;
case 39: return fan.fwt.Key.m_right;
case 46: return fan.fwt.Key.m_$delete;
case 33: return fan.fwt.Key.m_pageUp;
case 34: return fan.fwt.Key.m_pageDown;
case 36: return fan.fwt.Key.m_home;
case 35: return fan.fwt.Key.m_end;
case 45: return fan.fwt.Key.m_insert;
case 112: return fan.fwt.Key.m_f1;
case 113: return fan.fwt.Key.m_f2;
case 114: return fan.fwt.Key.m_f3;
case 115: return fan.fwt.Key.m_f4;
case 116: return fan.fwt.Key.m_f5;
case 117: return fan.fwt.Key.m_f6;
case 118: return fan.fwt.Key.m_f7;
case 119: return fan.fwt.Key.m_f8;
case 120: return fan.fwt.Key.m_f9;
case 121: return fan.fwt.Key.m_f10;
case 122: return fan.fwt.Key.m_f11;
case 123: return fan.fwt.Key.m_f12;
case 106: return fan.fwt.Key.m_keypadMult;
case 107: return fan.fwt.Key.m_keypadPlus;
case 109: return fan.fwt.Key.m_keypadMinus;
case 110: return fan.fwt.Key.m_keypadDot;
case 111: return fan.fwt.Key.m_keypadDiv;
case 96: return fan.fwt.Key.m_keypad0;
case 97: return fan.fwt.Key.m_keypad1;
case 98: return fan.fwt.Key.m_keypad2;
case 99: return fan.fwt.Key.m_keypad3;
case 100: return fan.fwt.Key.m_keypad4;
case 101: return fan.fwt.Key.m_keypad5;
case 102: return fan.fwt.Key.m_keypad6;
case 103: return fan.fwt.Key.m_keypad7;
case 104: return fan.fwt.Key.m_keypad8;
case 105: return fan.fwt.Key.m_keypad9;
case 106: return fan.fwt.Key.m_keypadEqual;
//case 13: return fan.fwt.Key.m_keypadEnter; same as enter
case 20: return fan.fwt.Key.m_capsLock;
case 144: return fan.fwt.Key.m_numLock;
case 145: return fan.fwt.Key.m_scrollLock;
case 19: return fan.fwt.Key.m_pause;
// case 46: return fan.fwt.Key.m_printScreen; cant get it on my computer
case 18: return fan.fwt.Key.m_alt;
case 16: return fan.fwt.Key.m_shift;
case 17: return fan.fwt.Key.m_ctrl;
case 91: return fan.fwt.Key.m_command; //the windows key
case 59: case 186: return fan.fwt.Key.fromMask(59); //;:
case 61: case 187: return fan.fwt.Key.fromMask(61); //=+
case 188: return fan.fwt.Key.fromMask(44); //,<
case 189: return fan.fwt.Key.fromMask(45); //-_ //in firefox it will be keypad.minus
case 190: return fan.fwt.Key.fromMask(46); //.>
case 191: return fan.fwt.Key.fromMask(47); ///?
case 192: return fan.fwt.Key.fromMask(96); //`~
case 219: return fan.fwt.Key.fromMask(91); //[{
case 220: return fan.fwt.Key.fromMask(92); //\|
case 221: return fan.fwt.Key.fromMask(93); //]}
case 222: return fan.fwt.Key.fromMask(39); //'"
default: return fan.fwt.Key.fromMask(keyCode);
}
}
fan.fwt.WidgetPeer.keyToCharCode = function(key)
{
var mask = key.m_mask & ~0x470000;
if(mask >= 65 && mask <= 90)
{
if(!key.isShift())
return mask + 32;
return mask;
}
if(key.isShift())
{
//Will do according us keyboard
switch(mask)
{
case fan.fwt.Key.m_num1.m_mask: return 33;// !
case fan.fwt.Key.m_num2.m_mask: return 64;// @
case fan.fwt.Key.m_num3.m_mask: return 35;// #
case fan.fwt.Key.m_num4.m_mask: return 36;// $
case fan.fwt.Key.m_num5.m_mask: return 37;// %
case fan.fwt.Key.m_num6.m_mask: return 94;// ^
case fan.fwt.Key.m_num7.m_mask: return 38;// &
case fan.fwt.Key.m_num8.m_mask: return 42;// *
case fan.fwt.Key.m_num9.m_mask: return 40;// (
case fan.fwt.Key.m_num0.m_mask: return 41;// )
case 59: return 58; // ;:
case 61: return 43; // =+
case 44: return 60; // ,<
case 45: return 95; // -_
case 46: return 62; // .>
case 47: return 63; // /?
case 96: return 126; // `~
case 91: return 123; // [{
case 92: return 124; // \|
case 93: return 125; // ]}
case 39: return 34; // '"
case fan.fwt.Key.m_keypadMult.m_mask: return 42; // *
case fan.fwt.Key.m_keypadPlus.m_mask: return 43; // +
case fan.fwt.Key.m_keypadMinus.m_mask: return 45;// -
case fan.fwt.Key.m_keypadDot.m_mask: return 127; //Java implemetation does this also, is this what we want
case fan.fwt.Key.m_keypadDiv.m_mask: return 47; // /
case fan.fwt.Key.m_keypad0.m_mask:
case fan.fwt.Key.m_keypad1.m_mask:
case fan.fwt.Key.m_keypad2.m_mask:
case fan.fwt.Key.m_keypad3.m_mask:
case fan.fwt.Key.m_keypad4.m_mask:
case fan.fwt.Key.m_keypad5.m_mask:
case fan.fwt.Key.m_keypad6.m_mask:
case fan.fwt.Key.m_keypad7.m_mask:
case fan.fwt.Key.m_keypad8.m_mask:
case fan.fwt.Key.m_keypad9.m_mask: return 0; //Java implemetation does this also, is this what we want
case fan.fwt.Key.m_keypadEqual.m_mask: return 61;// =
default:
}
}
else
{
switch(key.m_mask)
{
case fan.fwt.Key.m_num1.m_mask:
case fan.fwt.Key.m_num2.m_mask:
case fan.fwt.Key.m_num3.m_mask:
case fan.fwt.Key.m_num4.m_mask:
case fan.fwt.Key.m_num5.m_mask:
case fan.fwt.Key.m_num6.m_mask:
case fan.fwt.Key.m_num7.m_mask:
case fan.fwt.Key.m_num8.m_mask:
case fan.fwt.Key.m_num9.m_mask:
case fan.fwt.Key.m_num0.m_mask:
case 59: // ;:
case 61: // =+
case 44: //,<
case 45: //-_
case 46: //.>
case 47: ///?
case 96: //`~
case 91: //[{
case 92: //\|
case 93: //]}
case 39: //'"
return mask;
case fan.fwt.Key.m_keypadMult.m_mask: return 42; // *
case fan.fwt.Key.m_keypadPlus.m_mask: return 43; // +
case fan.fwt.Key.m_keypadMinus.m_mask: return 45;// -
case fan.fwt.Key.m_keypadDot.m_mask: return 46; // .
case fan.fwt.Key.m_keypadDiv.m_mask: return 47; // /
case fan.fwt.Key.m_keypad0.m_mask: return fan.fwt.Key.m_num0.m_mask;// 0
case fan.fwt.Key.m_keypad1.m_mask: return fan.fwt.Key.m_num1.m_mask;// 1
case fan.fwt.Key.m_keypad2.m_mask: return fan.fwt.Key.m_num2.m_mask;// 2
case fan.fwt.Key.m_keypad3.m_mask: return fan.fwt.Key.m_num3.m_mask;// 3
case fan.fwt.Key.m_keypad4.m_mask: return fan.fwt.Key.m_num4.m_mask;// 4
case fan.fwt.Key.m_keypad5.m_mask: return fan.fwt.Key.m_num5.m_mask;// 5
case fan.fwt.Key.m_keypad6.m_mask: return fan.fwt.Key.m_num6.m_mask;// 6
case fan.fwt.Key.m_keypad7.m_mask: return fan.fwt.Key.m_num7.m_mask;// 7
case fan.fwt.Key.m_keypad8.m_mask: return fan.fwt.Key.m_num8.m_mask;// 8
case fan.fwt.Key.m_keypad9.m_mask: return fan.fwt.Key.m_num9.m_mask;// 9
case fan.fwt.Key.m_keypadEqual.m_mask: return 61;// =
default:
}
}
return 0;
}
EDIT: small bug fix this.document.addEventListener("mouseup", mouseHandler, false->true);
jessevdamThu 28 Jul 2011
After doing this fix I got my app, which I initially made to run on the desktop running fine in the chrome browser :) and in firefox (but that is really slow).
It is small application to visualize networks.
But i think it is really big achievement to so easaly "convert" a normal app to a web app.
andyThu 28 Jul 2011
Woah thats a lot of code ;)
The key eventing should already be functional if you're working off tip. Its pretty straightforward - if any key listeners are attached to a widget - then his peer.elem configures tabIndex which makes that element a focusable node. See the changeset.
I'll take a look at pulling the key codes in when I get back from the beach week after next. Thanks for posting those.
jessevdamThu 28 Jul 2011
Thanks for the tabIndex thing. I did not knew that. I checked it and my app is now working in firefox, chrome and in safari.
jessevdam Thu 28 Jul 2011
I added support for key events. There is some extra code to direct the key events to the last selected "focused" widget, did not add tabbing yet. Since a canvas is not focusable in html 5.
Added support for most of the keycode in chrome and firefox (should also include IE), but tested it on chrome and firefox.
Added also charCode to it, although it does not take from the browser and is according default us keyboard.
Test the keyCode and charCode on both. The - in firefox is a keypad-. So shift- is not charcode _. Firefox under Ubuntu does not handle \' \^ \` \~ \" well because these are "escapee" characters.
Here is the code
EDIT: small bug fix this.document.addEventListener("mouseup", mouseHandler, false->true);
jessevdam Thu 28 Jul 2011
After doing this fix I got my app, which I initially made to run on the desktop running fine in the chrome browser :) and in firefox (but that is really slow).
It is small application to visualize networks.
But i think it is really big achievement to so easaly "convert" a normal app to a web app.
andy Thu 28 Jul 2011
Woah thats a lot of code ;)
The key eventing should already be functional if you're working off tip. Its pretty straightforward - if any key listeners are attached to a widget - then his
peer.elem
configurestabIndex
which makes that element a focusable node. See the changeset.I'll take a look at pulling the key codes in when I get back from the beach week after next. Thanks for posting those.
jessevdam Thu 28 Jul 2011
Thanks for the tabIndex thing. I did not knew that. I checked it and my app is now working in firefox, chrome and in safari.