Caps Lock on iOS only trigged key release or key press events.
When it's clicked it would only send keydown, and next time
it would only send keyup and so on. It should send both a key press
and a key release.
Also added the unit tests for macOS since those were missing.
Co-Authored-By: Alex Tanskanen <aleta@cendio.se>
There is no obvious choice what works best here, but this is what
TigerVNC has been doing for years without complaints. Let's follow
them until we get reports that this doesn't work well.
If using the extra keys always gives focus to the screen then an
on-screen keyboard would be closed. When using on-screen keyboards we
instead want to give focus to our virtual keyboard input element.
It seems Apple has fixed their buggy keyup events, so remove the
workaround and allow keys to be kept pressed again.
This is a revert of 9e99ce126ca8f6f350fa015c0e58d35103c62f7e.
The standards have unfortunatly caused some confusion between the Windows
key and the original Meta key. Try to handle the common case sanely at least.
A regression from 2afda54 and friends was that you couldn't use the
extra keys and then directly use the keyboard, you would have to click
in the session first.
This commit restores the correct behavior and also adds a visual queue
to the fact that the screen got the focus by fading the controlbar.
Makes it easier to understand what happens when a real element isn't
passed as a target to updateVisibility(). Also makes the code more
robust to future changes.
Co-authored-by: Alex Tanskanen <aleta@cendio.se>
Co-authored-by: Niko Lehto <nikle@cendio.se>
In the cursor emulation when deciding if the cursor should be hidden -
Instead of checking what's under the cursor, we check the element that
has capture.
This introduced another bug in the cursor emulation. The cursor did not
always disappear properly when using our cursor emulation together with
our setCapture polyfill. More specifically, we saw a problem when a
capture ended on an element without cursor emulation.
We solved this by introducing another visibility check on a timer in
the cursor emulation. However this led to yet another problem where
this timer conflicted with the timer in the setCapture polyfill.
We removed the timeout in the setCapture polyfill and created a
variable to make sure that all the events remaining in the queue can be
completed.
Co-authored-by: Alex Tanskanen <aleta@cendio.se>
Co-authored-by: Niko Lehto <nikle@cendio.se>
It's not obvious that we want to hide the cursor when we get a leave,
it depends on the element that we're leaving to. This makes the code
more robust.
Co-authored-by: Alex Tanskanen <aleta@cendio.se>
Co-authored-by: Niko Lehto <nikle@cendio.se>
The names of many variables were too similar. To make the code easier
to follow we renamed:
* _captureElem to _capturedElem
* _captureElemChanged() to _capturedElemChanged()
* captureElem to proxyElem
* elem to target
Co-authored-by: Alex Tanskanen <aleta@cendio.se>
Co-authored-by: Niko Lehto <nikle@cendio.se>
Toggling the enabled state is a remnant from an earlier version
of the code where we could determine if the the session is actually
clipped, and not just that the setting is enabled.
Right now we only change things based on the setting, so let's
completely hide the button when clipping is disabled.
Supports both classic cursor type and alpha cursor type. In classic
mode the server can send 'inverted' pixels for the cursor, our code
does not support this but handles these pixels as opaque black.
Co-authored-by: Samuel Mannehed <samuel@cendio.se>
It is not relevant for the connection stage so it should not have
been a constructor argument to begin with. Ship with a warning for
a release before we remove it.
The cursor object is only attached to our canvas whilst connecting,
so we need to make sure we don't try to update anything when were
not connected or we'll get a crash.
When compacting the receive buffer, we should only copy the bytes
between _rQi and _rQlen (the index of the first unread byte, and the
next write position).
Previously, we copied everything for _rQi up untill the end of the
buffer.
Previously, we would compact the buffer (moving unread data to the
start of the buffer) as follows:
- after processing a message, if there are zero unread bytes, just reset
the indices for first and last unread byte to zero
- else, if at least 1/8th of the buffer is used, copy remaining data to the beginning of the buffer
The second option is never actually necessary, as before inserting new data
into the array, we already check if there's enough free space, and
compact the buffer first if necessary. So we've been doing a lot of
copies that weren't actually needed. Let's not do that any more.
The Firefox workaround which checks for missing Alt key events may
synthesise new KeyboardEvents. On these events, checkAlt should not be
recursively triggered. Otherwise, we get "too much recursion" errors
whenever the Alt key is pressed.