diff options
author | Jeremy White <jwhite@codeweavers.com> | 2013-04-19 11:36:41 -0500 |
---|---|---|
committer | Jeremy White <jwhite@codeweavers.com> | 2013-04-19 11:36:41 -0500 |
commit | bcffac0aa49f60d60e4dcbf1a66fc2b9f8a0548b (patch) | |
tree | 11b0d0b21504deb5b8e3db31e5ce3dc99259f71b | |
parent | 12fe9ebb9640d22f37579a6e79542a94c48b3b3c (diff) |
Provide two levels of workaround for IE 10 cursor support.
The first approach is to use a moving image to simulate the cursor.
This does not work well, so a second approach, involving static
cursors is provided. That requires a site administrator to precreate
all the cursors that can be used by a particular application set.
A warning message strongly suggests using a different browser as well.
-rw-r--r-- | cursor.js | 6 | ||||
-rw-r--r-- | display.js | 2 | ||||
-rw-r--r-- | inputs.js | 9 | ||||
-rw-r--r-- | simulatecursor.js | 202 | ||||
-rw-r--r-- | spice.html | 1 | ||||
-rw-r--r-- | spice_auto.html | 1 |
6 files changed, 220 insertions, 1 deletions
@@ -88,5 +88,9 @@ SpiceCursorConn.prototype.set_cursor = function(cursor) var pngstr = create_rgba_png(cursor.header.height, cursor.header.width, cursor.data); var curstr = 'url(data:image/png,' + pngstr + ') ' + cursor.header.hot_spot_x + ' ' + cursor.header.hot_spot_y + ", default"; - document.getElementById(this.parent.screen_id).style.cursor = curstr; + var screen = document.getElementById(this.parent.screen_id); + screen.style.cursor = 'auto'; + screen.style.cursor = curstr; + if (window.getComputedStyle(screen, null).cursor == 'auto') + SpiceSimulateCursor.simulate_cursor(this, cursor, screen, pngstr); } @@ -721,6 +721,8 @@ function handle_mouseover(e) function handle_mouseout(e) { + if (this.sc && this.sc.cursor && this.sc.cursor.spice_simulated_cursor) + this.sc.cursor.spice_simulated_cursor.style.display = 'none'; this.blur(); } @@ -98,6 +98,15 @@ function handle_mousemove(e) DEBUG > 0 && this.sc.log_info("Discarding mouse motion"); } } + + if (this.sc && this.sc.cursor && this.sc.cursor.spice_simulated_cursor) + { + this.sc.cursor.spice_simulated_cursor.style.display = 'block'; + this.sc.cursor.spice_simulated_cursor.style.left = e.pageX - this.sc.cursor.spice_simulated_cursor.spice_hot_x + 'px'; + this.sc.cursor.spice_simulated_cursor.style.top = e.pageY - this.sc.cursor.spice_simulated_cursor.spice_hot_y + 'px'; + e.preventDefault(); + } + } function handle_mousedown(e) diff --git a/simulatecursor.js b/simulatecursor.js new file mode 100644 index 0000000..b1fce06 --- /dev/null +++ b/simulatecursor.js @@ -0,0 +1,202 @@ +"use strict"; +/* + Copyright (C) 2013 by Jeremy P. White <jwhite@codeweavers.com> + + This file is part of spice-html5. + + spice-html5 is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + spice-html5 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with spice-html5. If not, see <http://www.gnu.org/licenses/>. +*/ + +/*---------------------------------------------------------------------------- +** SpiceSimulateCursor +** Internet Explorer 10 does not support data uri's in cursor assignment. +** This file provides a number of gimmicks to compensate. First, if there +** is a preloaded cursor available, we will use that. Failing that, we will +** simulate a cursor using an image that is moved around the screen. +**--------------------------------------------------------------------------*/ +var SpiceSimulateCursor = { + +cursors : new Array(), +unknown_cursors : new Array(), +warned: false, + +add_cursor: function(sha1, value) +{ + SpiceSimulateCursor.cursors[sha1] = value; +}, + +unknown_cursor: function(sha1, curdata) +{ + if (! SpiceSimulateCursor.warned) + { + SpiceSimulateCursor.warned = true; + alert("Internet Explorer does not support dynamic cursors. " + + "This page will now simulate cursors with images, " + + "which will be imperfect. We recommend using Chrome or Firefox instead. " + + "\n\nIf you need to use Internet Explorer, you can create a static cursor " + + "file for each cursor your application uses. " + + "View the console log for more information on creating static cursors for your environment."); + } + + if (! SpiceSimulateCursor.unknown_cursors[sha1]) + { + SpiceSimulateCursor.unknown_cursors[sha1] = curdata; + console.log('Unknown cursor. Simulation required. To avoid simulation for this cursor, create and include a custom javascript file, and add the following line:'); + console.log('SpiceCursorSimulator.add_cursor("' + sha1 + '"), "<your filename here>.cur");'); + console.log('And then run following command, redirecting output into <your filename here>.cur:'); + console.log('php -r "echo urldecode(\'' + curdata + '\');"'); + } +}, + +simulate_cursor: function (spicecursor, cursor, screen, pngstr) +{ + var cursor_sha = hex_sha1(pngstr + ' ' + cursor.header.hot_spot_x + ' ' + cursor.header.hot_spot_y); + if (typeof SpiceSimulateCursor.cursors != 'undefined') + if (typeof SpiceSimulateCursor.cursors[cursor_sha] != 'undefined') + { + var curstr = 'url(' + SpiceSimulateCursor.cursors[cursor_sha] + '), default'; + screen.style.cursor = curstr; + } + + if (window.getComputedStyle(screen, null).cursor == 'auto') + { + SpiceSimulateCursor.unknown_cursor(cursor_sha, + SpiceSimulateCursor.create_icondir(cursor.header.width, cursor.header.height, + cursor.data.byteLength, cursor.header.hot_spot_x, cursor.header.hot_spot_y) + pngstr); + + document.getElementById(spicecursor.parent.screen_id).style.cursor = 'none'; + if (! spicecursor.spice_simulated_cursor) + { + spicecursor.spice_simulated_cursor = document.createElement('img'); + + spicecursor.spice_simulated_cursor.style.position = 'absolute'; + spicecursor.spice_simulated_cursor.style.display = 'none'; + spicecursor.spice_simulated_cursor.style.overflow = 'hidden'; + + spicecursor.spice_simulated_cursor.spice_screen = document.getElementById(spicecursor.parent.screen_id); + + spicecursor.spice_simulated_cursor.addEventListener('mousemove', SpiceSimulateCursor.handle_sim_mousemove); + + spicecursor.spice_simulated_cursor.spice_screen.appendChild(spicecursor.spice_simulated_cursor); + } + + spicecursor.spice_simulated_cursor.src = 'data:image/png,' + pngstr; + + spicecursor.spice_simulated_cursor.spice_hot_x = cursor.header.hot_spot_x; + spicecursor.spice_simulated_cursor.spice_hot_y = cursor.header.hot_spot_y; + + spicecursor.spice_simulated_cursor.style.pointerEvents = "none"; + } + else + { + if (spicecursor.spice_simulated_cursor) + { + spicecursor.spice_simulated_cursor.spice_screen.removeChild(spicecursor.spice_simulated_cursor); + delete spicecursor.spice_simulated_cursor; + } + } +}, + +handle_sim_mousemove: function(e) +{ + var retval; + var f = SpiceSimulateCursor.duplicate_mouse_event(e, this.spice_screen); + return this.spice_screen.dispatchEvent(f); +}, + +duplicate_mouse_event: function(e, target) +{ + var evt = document.createEvent("mouseevent"); + evt.initMouseEvent(e.type, true, true, e.view, e.detail, + e.screenX, e.screenY, e.clientX, e.clientY, + e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, e.button, e.relatedTarget); + return evt; +}, + +ICONDIR: function () +{ +}, + +ICONDIRENTRY: function(width, height, bytes, hot_x, hot_y) +{ + this.width = width; + this.height = height; + this.bytes = bytes; + this.hot_x = hot_x; + this.hot_y = hot_y; +}, + + +create_icondir: function (width, height, bytes, hot_x, hot_y) +{ + var i; + var header = new SpiceSimulateCursor.ICONDIR(); + var entry = new SpiceSimulateCursor.ICONDIRENTRY(width, height, bytes, hot_x, hot_y); + + var mb = new ArrayBuffer(header.buffer_size() + entry.buffer_size()); + var at = header.to_buffer(mb); + at = entry.to_buffer(mb, at); + + var u8 = new Uint8Array(mb); + var str = ""; + for (i = 0; i < at; i++) + { + str += "%"; + if (u8[i] < 16) + str += "0"; + str += u8[i].toString(16); + } + return str; +}, + +}; + +SpiceSimulateCursor.ICONDIR.prototype = +{ + to_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + dv.setUint16(at, 0, true); at += 2; + dv.setUint16(at, 2, true); at += 2; + dv.setUint16(at, 1, true); at += 2; + return at; + }, + buffer_size: function() + { + return 6; + } +}; + +SpiceSimulateCursor.ICONDIRENTRY.prototype = +{ + to_buffer: function(a, at) + { + at = at || 0; + var dv = new SpiceDataView(a); + dv.setUint8(at, this.width); at++; + dv.setUint8(at, this.height); at++; + dv.setUint8(at, 0); at++; /* color palette count, unused */ + dv.setUint8(at, 0); at++; /* reserved */ + dv.setUint16(at, this.hot_x, true); at += 2; + dv.setUint16(at, this.hot_y, true); at += 2; + dv.setUint32(at, this.bytes, true); at += 4; + dv.setUint32(at, at + 4, true); at += 4; /* Offset to bytes */ + return at; + }, + buffer_size: function() + { + return 16; + } +}; @@ -44,6 +44,7 @@ <script src="display.js"></script> <script src="main.js"></script> <script src="inputs.js"></script> + <script src="simulatecursor.js"></script> <script src="cursor.js"></script> <script src="thirdparty/jsbn.js"></script> <script src="thirdparty/rsa.js"></script> diff --git a/spice_auto.html b/spice_auto.html index 5e4bedc..788202e 100644 --- a/spice_auto.html +++ b/spice_auto.html @@ -43,6 +43,7 @@ <script src="display.js"></script> <script src="main.js"></script> <script src="inputs.js"></script> + <script src="simulatecursor.js"></script> <script src="cursor.js"></script> <script src="thirdparty/jsbn.js"></script> <script src="thirdparty/rsa.js"></script> |