Web Dashboard APIs
OpenKneeboard currently has a very limited JavaScript API for Web Dashboard tabs; this is likely to be extended in the future. Future plans are primarily being discussed in issue #240
Table of Contents
- Detecting OpenKneeboard
- Transparency
- JavaScript APIs
- OpenDeveloperToolsWindow
- Experimental JavaScript APIs
Detecting OpenKneeboard
There are several ways to detect if your web page is being accessed within OpenKneeboard’s “Web Dashboard” tabs:
- the user agent string contains
OpenKneeboard/a.b.c.d
, wherea.b.c.d
is the version number window.OpenKneeboard
is set, and is a valid object- DEPRECATED - removed in v1.9: the
<body>
element has theOpenKneeboard
class - DEPRECATED - removed in v1.9: the
<body>
element has theOpenKneeboard_WebView2
class; this also indicates that OpenKneeboard is using Microsoft’s Chromium-based-Edge ‘WebView2’ browser engine
OpenKneeboard v1.9 and above no longer add CSS classes to the body, as this can lead to compatibility problems. The easiest way to restore the old behavior is to add the following to your page:
if (windows.OpenKneeboard) {
document.body.classList.add("OpenKneeboard");
}
The window.OpenKneeboard
object is loaded before any scripts on the page start executing.
Transparency
OpenKneeboard’s virtual browser window is fully transparent; this allows full RGBA transparency via standard CSS, e.g.:
body.OpenKneeboard {
background-color: transparent;
}
JavaScript APIs
All APIs are methods on the window.OpenKneeboard
object; it is best practice to confirm that OpenKneeboard is being used and the API you want is available; for example, if you want to call SetPreferredPixelSize()
, a safe way to call it is like this:
if (window.OpenKneeboard?.SetPreferredPixelSize) {
window.OpenKneeboard.SetPreferredPixelSize(width, height);
}
In v1.9 and above, window.OpenKneeboard
can usually be accessed just as OpenKneeboard
.
Conventions in v1.9+
The JS API is extended and improved in v1.9 and above:
Functions have consistent return behavior:
- they return a
Promise
, which can be used withawait
,promise.then()
, or other standard techniques - if the success value is undocumented or documented as
any
, it may contain additional information intended to inform you, but may change without warning between versions. Do not write code that depends on a particular value or type - on failure:
- the error will be logged to the developer tools console
- the
Promise
will be rejected with anOpenKneeboardAPIError
The OpenKneeboardAPIError
extends the standard JavaScript Error
class, adding an apiMethodName
string property; for example:
// In v1.9+:
try {
/* ... some code here ... */
await OpenKneeboard.SomeAPI(/* ... */ );
/* ... some more code ... */
} catch (error) {
if (error instanceof OpenKneeboardAPIError) {
// Logs "OpenKneeboard.SomeAPI()" and an explanation
console.log(error.apiMethodName, error.message);
}
}
A note on await
Several OpenKneeboard API functions return a Promise
; the examples will use the await
syntac for these, e.g.:
try {
await OpenKneeboard.DoSomething();
DoSomethingElse();
} catch (error) {
HandleError(error);
}
As these are standard Promise
objects, if you prefer, you can use the traditional syntax instead:
OpenKneeboard.DoSomething()
.then(function(result) { DoSomethingElse(); })
.catch(function(error) {HandleError(error); });
TypeScript
In v1.9 and above, TypeScript definitions are included both in data
subfolder of the OpenKneeboard source tree, and in the share\doc
subfolder of an OpenKneeboard installation.
Unless you are intentionally using an experimental API, you should only include OpenKneeboard.d.ts
in your project; the various OpenKneeboard-Experimental-*.d.ts
files define additional features that are not usually available.
If you are not familiar with TypeScript, you may still want to copy the OpenKneeboard.d.ts
file into your project - some IDEs will automatically use it to provide better help while you are writing your JavaScript code.
All of OpenKneeboard’s stable APIs are defined in OpenKneeboard.d.ts
.
SetPreferredPixelSize
Set the preferred pixel size and aspect ratio for this page.
// Syntax (v1.8):
window.OpenKneeboard.SetPreferredPixelSize(width: number, height: number): undefined;
// Example (v1.8):
window.OpenKneeboard.SetPreferredPixelSize(1024, 768);
// Syntax (v1.9+):
OpenKneeboard.SetPreferredPixelSize(width: number, height: number): Promise<any>;
// Example (v1.9+):
await OpenKneeboard.SetPreferredPixelSize(1024, 768);
width
and height
:
- must be an integer number of pixels
- must be greater than or equal to 1
- must be less than or equal to
D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION
(16384 as of Direct3D 11.1).
In v1.9+, awaiting/resolving the promise is optional, but does provide a means to detect success or failure; for compatibility, it can also be accessed via the window.OpenKneeboard
GetVersion
This requires OpenKneeboard v1.9 and above.
// Syntax:
OpenKneeboard.GetVersion(): Promise<Object>;
// Example:
const okbVersion = await OpenKneeboard.GetVersion();
The promise resolves to an object like the following:
{
"Components": {
"Major": 1,
"Minor": 9,
"Patch": 0,
"Build": 0
},
"HumanReadable": "v1.9.0+local",
"IsGitHubActionsBuild": false,
"IsStableRelease": false,
"IsTaggedVersion": false
}
Components
: individual parts of the OpenKneeboard as numbers; you probably want to use these for any version-dependent logic in your code. Released OpenKneeboard versions have versions of the form vMajor.Minor.Patch.Build or vMajor.Minor.Patch+GHABuild.Build
is the run number from GitHub actions; it is 0 for local developer builds.HumanReadable
: if you display an OpenKneeboard version number to the user in any form, you should use this string. For example,v1.8.2-rc1
is much clearer to the user thanv1.8.2.2057
(the actual v1.8.2 release isv1.8.2.2080
).IsGitHubActionsBuild
: whether or not this version of OpenKneeboard was built automatically through continuous integration; otherwise, it is a local developer buildIsStableRelease
: true for builds made on GitHub Actions from a stable release tag; false for all other builds.IsTaggedVersion
: true for builds made on GitHub Actions from a release tag, false for all other builds. This differs fromIsStableRelease
for tagged pre-release builds; for example, an automated build ofv1.9.0-rc1
would be a tagged version, but not a stable release.
The two forms of version number are used because:
- Some Windows features only support the 4-numbers form
- The string version is much more understandable to people than the 4-numbers form
OpenDeveloperToolsWindow
Opens the MS Edge developer tools window; requires OpenKneeboard v1.9.
OpenKneeboard.OpenDeveloperToolsWindow();
Experimental JavaScript APIs
These features will be changed without notice, and in any update, including patch releases; you should avoid using them in released software if possible; reach out in #code-talk
on Discord before releasing software that uses them.
If you want to use an experimental API with the goal of switching to a stable API when it is used, the best approach is to wrap enabling it in a try
/catch
, e.g.:
try {
await OpenKneeboard.EnableExperimentalFeature('foo', 1234);
TurnOnMyUseOfThisExperimentalFeature();
} catch (ex) {
console.log("Failed to initialize experimental feature foo", ex);
}
Experimental features are identified by a name, and a version number (usually YYYYMMDDnn
, where ‘nn’ increments if there are multiple revisions within a day); they must be explicitly enabled.
EnableExperimentalFeature
// Syntax:
OpenKneeboard.EnableExperimentalFeature(name: string, version: number): Promise<any>;
// Example:
await OpenKneeboard.EnableExperimentalFeature("foo", 2024071801);
On success, the Promise will resolve to a JSON object, which may contain additional information for debugging.
On failure, the Promise will be rejected, with a string error message indicating the reason. Likely reasons for failure are unrecognized features or versions.
EnableExperimentalFeatures
Enable multiple features in one go.
// Example:
await OpenKneeboard.EnableExperimentalFeature([
{ name: "Foo", version: 1234 },
{ name: "Bar", version: 5678 },
]);
Return values will be the same; if any feature names/versions are not supported, the function will indicate failure - however, preceding features may have been enabled
‘cursor’ event
This feature requires:
- OpenKneeboard v1.9 or above
- experimental feature:
RawCursorEvents
version2024071802
- experimental feature:
SetCursorEventsMode
version2024071801
This event provides access to OpenKneeboard’s raw cursor events, bypassing browser mouse emulation.
// Example:
OpenKneeboard.addEventListener('cursor', (ev) => { console.log(ev.detail); });
await OpenKneeboard.EnableExperimentalFeatures([
{name: "RawCursorEvents", version: 2024071802},
{name: "SetCursorEventsMode", version: 2024071801},
]);
await OpenKneeboard.SetCursorEventsMode("Raw");
For version 2024071802 of the experimental feature, the events will be of this form:
{
buttons: int,
position: { x: number, y: number },
touchState: "NearSurface" | "NotNearSurface" | "TouchingSurface",
}
These events are used for both tablet and mouse events.
buttons
: bitmask; the lowest bit is left click or the tablet pen tip. Other buttons are additional mice buttons or buttons on the tablet (not pen)position
: positions in pixelsx
andy
are floating point; especially with a tablet, the cursor can be positioned between two logical pixels
touchState
- for tablets, this is self-descriptive
- for mice,
NotNearSurface
means “outside of the web page’s area”, andTouchingSurface
means ‘clicking’ - you should usually hide any cursors you may be showing if the state changes to
NotNearSurface
An example/debugging tool - api-example-RawCursorEvents.html
is included in the data
folder of the OpenKneeboard source tree, or the share\doc\
subfolder of an OpenKneeboard installation.
Change history
2024071801 -> 2024071802
- enabling the feature now only makes the cursor event mode available, it does not automatically switch to it
- it is no longer incompatible with the
DoodlesOnly
feature
DoodlesOnly
This feature requires:
- OpenKneeboard v1.9 or above
- experimental feature:
DoodlesOnly
version2024071802
Enabling this feature disables the standard mouse emulation, and instead uses OpenKneeboard’s standard “draw on top” behavior, letting users take notes or sketch on top of your content.
As the mouse emulation is disabled, after enabling this feature, it is no longer possible for the user to interact with your web page, including the scroll bars; it should only be used for single-screen content.
// Example:
await OpenKneeboard.EnableExperimentalFeatures([
{name: "DoodlesOnly", version: 2024071802},
{name: "SetCursorEventsMode", version: 2024071801},
]);
await OpenKneeboard.SetCursorEventsMode("DoodlesOnly");
Change history
2024071801 -> 2024071802
- enabling the feature now only makes the cursor event mode available, it does not automatically switch to it
- it is no longer incompatible with the
RawCursorEvents
feature
SetCursorEventsMode
This feature requires:
- OpenKneeboard v1.9 or above
- experimental feature:
SetCursorEventsMode
version2024071801
// Syntax:
OpenKneeboard.SetCursorEventsMode("MouseEmulation" | "DoodlesOnly" | "Raw"): Promise<any>;
// Example:
await OpenKneeboard.EnableExperimentalFeatures([
{name: "RawCursorEvents", version: 2024071802},
{name: "SetCursorEventsMode", version: 2024071801},
]);
await OpenKneeboard.SetCursorEventsMode("Raw");
- setting the mode to
"Raw"
requiresRawCursorEvents
version2024071802
- setting the mode to
"DoodlesOnly"
requiresDoodlesOnly
version2024071802
An example/debugging tool - api-example-RawCursorEvents.html
is included in:
- the
data
folder of the OpenKneeboard source tree - the
share\doc\
subfolder of an OpenKneeboard installation.
Page-Based Web Applications
This allows creating a web page that works like a native OpenKneeboard tab type with multiple pages, instead of a potentially-scrollable web view.
This functionality is documented on a separate page.