QEMU RFB extension - rfb.js and input.js changes

In input.js, a new keyboard handler was added to deal exclusively
with the QEMU key event extension. '_onKeyPress()' signature
was changed to allow the same method to treat both cases.

The extension will only be enabled if the browser has support
for the KeyboardEvent.code property.

Changes in rfb.js:

- added a new extension code, QEMUExtendedKeyEvent, value -258.

- handleKeyPress now receives 'keyevent' instead of 'keysym' and
'down'. Both values are retrieved from keyevent as they were
in the previous signature. This method now can send QEMU RFB
extended key messages if the flag was set to 'true'.

- tests/test.rfb.js were changed folowing the onKeyPress() signature
change.

- added a new function to send the QEMU extended key message.

Signed-off-by: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com>
This commit is contained in:
Daniel Henrique Barboza 2016-04-11 07:11:05 -03:00
parent 7ab542ef74
commit 8d09ab06f4
3 changed files with 81 additions and 6 deletions

View File

@ -51,10 +51,18 @@ var Keyboard, Mouse;
if (this._onKeyPress) { if (this._onKeyPress) {
Util.Debug("onKeyPress " + (e.type == 'keydown' ? "down" : "up") + Util.Debug("onKeyPress " + (e.type == 'keydown' ? "down" : "up") +
", keysym: " + e.keysym.keysym + "(" + e.keysym.keyname + ")"); ", keysym: " + e.keysym.keysym + "(" + e.keysym.keyname + ")");
this._onKeyPress(e.keysym.keysym, e.type == 'keydown'); this._onKeyPress(e);
} }
}, },
setQEMUVNCKeyboardHandler: function () {
this._handler = new QEMUKeyEventDecoder(kbdUtil.ModifierSync(),
TrackQEMUKeyState(
this._handleRfbEvent.bind(this)
)
);
},
_handleKeyDown: function (e) { _handleKeyDown: function (e) {
if (!this._focused) { return true; } if (!this._focused) { return true; }

View File

@ -58,7 +58,8 @@ var RFB;
['ExtendedDesktopSize', -308 ], ['ExtendedDesktopSize', -308 ],
['xvp', -309 ], ['xvp', -309 ],
['Fence', -312 ], ['Fence', -312 ],
['ContinuousUpdates', -313 ] ['ContinuousUpdates', -313 ],
['QEMUExtendedKeyEvent', -258 ]
]; ];
this._encHandlers = {}; this._encHandlers = {};
@ -129,6 +130,9 @@ var RFB;
this._viewportDragPos = {}; this._viewportDragPos = {};
this._viewportHasMoved = false; this._viewportHasMoved = false;
// QEMU Extended Key Event support - default to false
this._qemuExtKeyEventSupported = false;
// set the default value on user-facing properties // set the default value on user-facing properties
Util.set_defaults(this, defaults, { Util.set_defaults(this, defaults, {
'target': 'null', // VNC display rendering Canvas object 'target': 'null', // VNC display rendering Canvas object
@ -560,9 +564,22 @@ var RFB;
} }
}, },
_handleKeyPress: function (keysym, down) { _handleKeyPress: function (keyevent) {
if (this._view_only) { return; } // View only, skip keyboard, events if (this._view_only) { return; } // View only, skip keyboard, events
var down = (keyevent.type == 'keydown');
if (this._qemuExtKeyEventSupported) {
var scancode = XtScancode[keyevent.code];
if (scancode) {
var keysym = keyevent.keysym;
RFB.messages.QEMUExtendedKeyEvent(this._sock, keysym, down, scancode);
} else {
Util.Error('Unable to find a xt scancode for code = ' + keyevent.code);
}
} else {
keysym = keyevent.keysym.keysym;
RFB.messages.keyEvent(this._sock, keysym, down); RFB.messages.keyEvent(this._sock, keysym, down);
}
}, },
_handleMouseButton: function (x, y, down, bmask) { _handleMouseButton: function (x, y, down, bmask) {
@ -1348,6 +1365,42 @@ var RFB;
sock.flush(); sock.flush();
}, },
QEMUExtendedKeyEvent: function (sock, keysym, down, keycode) {
function getRFBkeycode(xt_scancode) {
var upperByte = (keycode >> 8);
var lowerByte = (keycode & 0x00ff);
if (upperByte === 0xe0 && lowerByte < 0x7f) {
lowerByte = lowerByte | 0x80;
return lowerByte;
}
return xt_scancode
}
var buff = sock._sQ;
var offset = sock._sQlen;
buff[offset] = 255; // msg-type
buff[offset + 1] = 0; // sub msg-type
buff[offset + 2] = (down >> 8);
buff[offset + 3] = down;
buff[offset + 4] = (keysym >> 24);
buff[offset + 5] = (keysym >> 16);
buff[offset + 6] = (keysym >> 8);
buff[offset + 7] = keysym;
var RFBkeycode = getRFBkeycode(keycode)
buff[offset + 8] = (RFBkeycode >> 24);
buff[offset + 9] = (RFBkeycode >> 16);
buff[offset + 10] = (RFBkeycode >> 8);
buff[offset + 11] = RFBkeycode;
sock._sQlen += 12;
sock.flush();
},
pointerEvent: function (sock, x, y, mask) { pointerEvent: function (sock, x, y, mask) {
var buff = sock._sQ; var buff = sock._sQ;
var offset = sock._sQlen; var offset = sock._sQlen;
@ -2259,6 +2312,16 @@ var RFB;
compress_lo: function () { compress_lo: function () {
Util.Error("Server sent compress level pseudo-encoding"); Util.Error("Server sent compress level pseudo-encoding");
},
QEMUExtendedKeyEvent: function () {
this._FBU.rects--;
var keyboardEvent = document.createEvent("keyboardEvent");
if (keyboardEvent.code !== undefined) {
this._qemuExtKeyEventSupported = true;
this._keyboard.setQEMUVNCKeyboardHandler();
} }
},
}; };
})(); })();

View File

@ -1927,7 +1927,11 @@ describe('Remote Frame Buffer Protocol Client', function() {
}); });
it('should send a key message on a key press', function () { it('should send a key message on a key press', function () {
client._keyboard._onKeyPress(1234, 1); var keyevent = {};
keyevent.type = 'keydown';
keyevent.keysym = {};
keyevent.keysym.keysym = 1234;
client._keyboard._onKeyPress(keyevent);
var key_msg = {_sQ: new Uint8Array(8), _sQlen: 0, flush: function () {}}; var key_msg = {_sQ: new Uint8Array(8), _sQlen: 0, flush: function () {}};
RFB.messages.keyEvent(key_msg, 1234, 1); RFB.messages.keyEvent(key_msg, 1234, 1);
expect(client._sock).to.have.sent(key_msg._sQ); expect(client._sock).to.have.sent(key_msg._sQ);