Cameron Cawley
stdlib: Added SDL_round, SDL_roundf, SDL_lround and SDL_lroundf
The default implementation is based on the one used in the Windows RT video driver.
Keep Semaphore Kernel Object impl for Windows 7 and older - choose at runtime
v2: - Fix mixed int/LONG types
- Reorder definitions
- Add missing include
v3: - Use `GetModuleHandle()` to load the API Set
v2: - Add SRW definitions as suggested by Ozkan Sezer
Allows building against older platform headers.
- Rename "hidden" function parameter `mutex_` to `_mutex`
v3: - Use GetModuleHandle instead of LoadLibrary
- Fix typo in comment
SDL_systhread.c and SDL_syslocale.c used to call LoadLibrary() without
calling FreeLibrary() later. GetModuleHandleW() should always succeed
because GetModuleHandleW() itself is imported from kernel32.dll and we
don't need to bother releasing it.
.. so that KMSDRM_CreateDevice() can fail and SDL_VideoInit() would
move on to next bootstrap member which is kmsdrm_legacy. hopefully
fixes bug #5393.
Substring
I was trying the KMSDRM video backend with some very simple programs that were working ok on 2.0.12. The same code won?t work on the current dev branch and I get:
DEBUG: check_modesetting: probing ?/dev/dri/card0?
DEBUG: /dev/dri/card0 connector, encoder and CRTC counts are: 4 5 6
DEBUG: check_modesetting: probing ?/dev/dri/card0?
DEBUG: /dev/dri/card0 connector, encoder and CRTC counts are: 4 5 6
DEBUG: KMSDRM_VideoInit()
DEBUG: Opening device /dev/dri/card0
DEBUG: Opened DRM FD (3)
DEBUG: no atomic modesetting support.
DEBUG: Video subsystem has not been initialized
INFO: Using SDL video driver: (null)
DEBUG: Video subsystem has not been initialized
After carefully checking, the radeon driver doesn?t support atomic modesetting. That?s not the only problem : the same happens with the amdgpu driver if we disable Display Core (kernel parameter amdgpu.dc=0, which is required to get analogue outputs working).
This is a major regression in the KMSDRM driver.
Using atomic mode setting is great, but having no fallback to the "standard KMS" is bad.
pj5085
I added some printf to verify the math being done. Of the three joysticks I have, it works correctly for at least two, and seems to work correctly for the third. I say "seems to" because, for the third joystick, the values never go through the AxisCorrect function, and thus never hit my printf statements, even though they did in the version I wrote my patch against. I'm not sure what's going on there, but it at least seems to be working correctly in as much as I can tell.
I note this result in particular, for an SNES Gamepad (min=0, max=255):
Joystick value 0 becomes -32768
Joystick value 127 becomes 0
Joystick value 255 becomes 32767
Without the code that forces a zero point, the 127 input value would become -129, so I think you see why I added that code to turn it into zero. However, I think Kai Krakow has a point about how SDL shouldn't assume that there should be a center.
Obviously in the majority of cases there actually should be a center, and the code that turns that 127 into an actual 0 is creating only a 0.2% error over 0.4% of this joystick's range. However, what if there is an axis that is some kind of special control, like a 4-position switch, and, for whatever reason, the joystick reports it as an axis with 4 possible values, 0 to 3? In that case, mutilating the two center values to the same value is much more of an error and and turns that 4-position switch into a 3-position switch. If any joystick does this with a 2-position switch, then this code would render that control entirely useless as it would report the same value with the switch in either position. Obviously the code could require that there be at least N possible values, to guess whether something is a proper axis or just some kind of switch, but the choice of N would be arbitrary and that's ugly.
I guess the real problem here is that my gamepad is just kind of broken. It should be reporting a range of -1 to +1 since that's what it actually does. Also, as Kai Krakow points out, it's probably not SDL's place to fix broken hardware. I'll add that, if SDL does fix broken hardware, it should probably actually know that it's broken rather than be merely guessing that it is.
So, to the extent that SDL is able to do stuff like this, perhaps it's something better left for the user to configure in some kind of config file.
pj5085
It occurred to me that my simple patch that comments out a few lines of code does not correctly remove the dead zone since the calculation presumably assumes the dead zone has been cut out of the range. Then, while looking into how to make it output the correct range of values, I realized SDL wasn't returning the correct range of values to begin with.
This line of code was already present:
printf("Values = { %d, %d, %d, %d, %d }\n", absinfo.value, absinfo.minimum, absinfo.maximum, absinfo.fuzz, absinfo.flat);
For my joystick this yeilds:
Values = { 0, -127, 127, 0, 15 }
Then this code calculates the coefficients:
In SDL1:
joystick->hwdata->abs_correct[i].coef[0] = (absinfo.maximum + absinfo.minimum) / 2 - absinfo.flat;
joystick->hwdata->abs_correct[i].coef[1] = (absinfo.maximum + absinfo.minimum) / 2 + absinfo.flat;
t = ((absinfo.maximum - absinfo.minimum) / 2 - 2 * absinfo.flat);
if ( t != 0 ) {
joystick->hwdata->abs_correct[i].coef[2] = (1 << 29) / t;
} else {
joystick->hwdata->abs_correct[i].coef[2] = 0;
}
In SDL2:
joystick->hwdata->abs_correct[i].coef[0] = (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat;
joystick->hwdata->abs_correct[i].coef[1] = (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat;
t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat);
if (t != 0) {
joystick->hwdata->abs_correct[i].coef[2] = (1 << 28) / t;
} else {
joystick->hwdata->abs_correct[i].coef[2] = 0;
}
Neither calculates the correct coefficients for the code in the AxisCorrect function.
In SDL1:
if ( value > correct->coef[0] ) {
if ( value < correct->coef[1] ) {
return 0;
}
value -= correct->coef[1];
} else {
value -= correct->coef[0];
}
value *= correct->coef[2];
value >>= 14;
In SDL2:
value *= 2;
if (value > correct->coef[0]) {
if (value < correct->coef[1]) {
return 0;
}
value -= correct->coef[1];
} else {
value -= correct->coef[0];
}
In SDL1, the calculated coefficients are coef[0]=15, coef[1]=-15 and coef[2]=5534751. So with a full-scale input of 127, it calculates an output value of 37835, which is considerably out of range.
In SDL2, the calculated coefficients are coef[0]=30, coef[1]=-30, and coef[2]=1383687. So with a full-scale input of 127, it calculates the same output value of 37835.
I tested it with the 3 joysticks I have, and it produces out-of-range values for all of them.
Anyway, since dead zones are garbage, I just deleted all of that junk and wrote some code that takes the absinfo.minimum and absinfo.maximum values and uses them to scale the axis range to -32767 through +32767.
I also made it detect when a range doesn't have an integer center point, e.g. the center of -128 to + 127 is -0.5. In such cases, if either value to the side of the center is provided, it zeros it, but it otherwise doesn't implement any kind of dead zone. This seemed important with my gamepad which provides only the values of 0, 127, and 255, since without this hack it would never be centered.
Also, the previous minimum output value was -32768, but as that creates an output range that has no true center, I changed the minimum value to -32767.
I tested it with the 3 joystick devices I have and it seems to create correct values for all of them.
Added a hint to control whether a separate thread should be used for joystick events.
This is off by default because dispatching messages in other threads appears to cause problems on some versions of Windows.
- SDL_video.c (SDL_ShowMessageBox): replace messageboxdata, set title
or message field to "" if either of them is NULL.
- SDL_video.c (SDL_ShowSimpleMessageBox): set title or message to ""
if either of them is NULL for EMSCRIPTEN builds.
- SDL_bmessagebox.cc: add empty string check along with NULL check for
title and message fields.
- SDL_windowsmessagebox.c (AddDialogString): remove NULL string check
- SDL_windowsmessagebox.c (AddDialogControl): add empty string check
along with the NULL check.
- SDL_x11messagebox.c: revert commit 677c4cd68069
- SDL_os2messagebox.c: revert commit 2c2a489d76e7
- test/testmessage.c: Add NULL title and NULL message tests.
Joel Linn
TLDR; https://godbolt.org/z/43fd8G
Let's deduce this from C++ reference code:
https://docs.microsoft.com/en-us/cpp/cppcx/wrl/how-to-activate-and-use-a-windows-runtime-component-using-wrl?view=msvc-160
At the bottom of the page there is this snippet:
```
int wmain()
{
/* ... more code ... */
// Get the domain part of the URI.
HString domainName;
hr = uri->get_Domain(domainName.GetAddressOf());
if (FAILED(hr))
{
return PrintError(__LINE__, hr);
}
// Print the domain name and return.
wprintf_s(L"Domain name: %s\n", domainName.GetRawBuffer(nullptr));
// All smart pointers and RAII objects go out of scope here.
}
```
`HString` is defined in `corewrappers.h` and the call chain for the destructor is:
`~HString() -> Release() -> ::WindowsDeleteString()`
QED
Vincent Hamm
Xcode11 and ios13 added support for metal simulator.
Here is a quick and dirty patch to enable it. Pretty early and only tested on a few samples for now. Required mostly to enable metal support on correct version of ios, generate simulator compatible shaders and enforce buffer alignments on simulator (same as osx).
If we fail to connect to the the pa server, we have an assigned context
and mainloop that isn't connected. So, when PULSEAUDIO_pa_context_disconnect
is called, pa asserts and crashes the application.
Assertion 'pa_atomic_load(&(c)->_ref) >= 1' failed at pulse/context.c:1055, function pa_context_disconnect(). Aborting.
Joel Linn
Eliminate additional heap allocation for short-lived HSTRINGs.
Uses `WindowsCreateStringReference()` to disable reference counting and memory management by the Window Runtime.
Ivan Mogilko
With SDL 2.0.12 under MS Windows, if the window is partially offscreen calling SDL_SetWindowGrab(w, SDL_TRUE) works, but subsequent call to SDL_SetWindowGrab(w, SDL_FALSE) does not work.
I tested this in both real program, and a small test app, where unlocking cursor worked perfectly while window is fully in desktop bounds, but did not work if it was at least few pixels outside.
For the reference, following code is enough to reproduce the issue:
#include <windows.h>
#include <SDL.h>
int WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd)
{
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* w = SDL_CreateWindow("", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 400, 0);
bool grabbed = false;
bool want_quit = false;
while (!want_quit)
{
SDL_Event event;
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT: want_quit = true; break;
case SDL_KEYDOWN:
if (event.key.keysym.scancode == SDL_SCANCODE_SPACE)
{
SDL_SetWindowGrab(w, static_cast<SDL_bool>(!grabbed));
grabbed = !grabbed;
}
}
}
}
SDL_DestroyWindow(w);
SDL_Quit();
return 0;
}
Mathieu Eyraud
SDL dynamically loads libusb but does not check the return value of 'SDL_LoadFunction'.
Also libusb is loaded and initialized several time because 'SDL_hidapi_wasinit' is never set to true.
I made a patch if you want to test:
- check that 'hid_init' is called once and only once,
- check return value of 'hid_init',
- check return value of 'SDL_LoadFunction',
- check return value of 'SDL_malloc',
- add some debug logging.
On older mac, where METAL Renderer METAL fails to create, it allows to switch back to OpenGL SDL_Renderer
by re-creating the window (METAL flags was previously persistent).
This can happen if the application has not yet processed SDL_JOYDEVICEADD when
the same joystick is removed. It may also happen if two joysticks are added
and the second joystick is removed before the first joystick's SDL_JOYDEVICEADD
has been processed by the application.
Joel Linn
Currently the rawinput driver always reports a device as "wired". This changes that to "unknown" and updates it once the device is correlated with xinput.
Most of the raw input events are dispatched in the main windows message loop. We only dispatch device change messages separately when we need them to be completely up to date.
It's legitimate to have a surface with 0 width or height (null 'pixels' pointer).
But calling SDL_FillRects would wrongly set the error "You must lock the surface".
src/joystick/windows/SDL_rawinputjoystick.c: In function 'RAWINPUT_HandleStatePacket':
src/joystick/windows/SDL_rawinputjoystick.c:1343:9: warning: suggest explicit braces to avoid ambiguous 'else'
multiply gyro values by sensitivity
When the hardware calibration fails, values read from sensors need to be multiplied by default sensitivity (16 for gyro, 1 for accelerometer).
Simon McVittie
When watching for hotplug events we can poll the inotify fd, but we
still need to scan /dev/input once per process, otherwise we'll fail
to detect devices that were already connected.
Flatpak[1] and pressure-vessel[2] are known to use user namespaces,
therefore udev event notification via netlink won't work reliably.
Both frameworks provide a filesystem API that libraries can use to
detect them. Do that, and automatically fall back from udev-based
device discovery to the inotify-based fallback introduced in Bug #5337.
[1] <https://flatpak.org/>
[2] <https://gitlab.steamos.cloud/steamrt/steam-runtime-tools/-/tree/master/pressure-vessel>
Signed-off-by: Simon McVittie <smcv@collabora.com>
Alex S
Evdev headers aren't actually included in the base system (well, it has a private copy), they are available through the devel/evdev-proto port instead. We also have devel/libinotify and devel/libudev-devd shims, I didn't verify whether they work with SDL.
This fixes bad report parsing for various newer Xbox controllers, and this driver is now preferred over XInput, since it handles more than 4 controllers.
C.W. Betts
This patch adds support to the GameController framework on macOS Big Sur and later, adding support for MFi controllers as well as rumble support for PS4 and Xbox One. There is some code to make sure that the IOKit joystick handler doesn't include two controllers at once.
While the GameController framework is present in earlier versions of macOS, there was no public, approved way of checking if a specific IOHIDDevice is a controller that GameController could handle. This was changed in Big Sur.
Added support for the PS4 controller gyro and accelerometer on iOS and HIDAPI drivers
Also fixed an issue with the accelerometer on iOS having inverted axes
As the name suggests, the hint should only apply to SDL_THREAD_PRIORITY_TIME_CRITICAL
The resulting priorities for my current distro result in these values:
| High | Time Critical
Hint |--------------|-----------------
0 | P=10 N=-10 | P=5 N=-15
1 | P=10 N=-10 | P=-21 N=0
Spooky
For some reason the Logitech Extreme 3D joystick was added to SDL_gamecontrollerdb.h in the linux section only.
This breaks the joystick in linux as it is not a gamepad. I am unable to correctly use or map the Logitech Exteme 3D joystick in games that use SDL2 in linux.
Please remove Logitech Extreme 3D from SDL_gamecontrollerdb.h Linux section. It is a joystick not a gamepad.
Bart van der Werf
When directinput fails to load, but a controlller is plugged in, an access violation happens.
This is due to IEventHandler_CRawGameControllerVtbl_InvokeAdded calling SDL_DINPUT_JoystickPresent which does not check if dinput is assigned signalling initialization of directinput.
Joel Linn
This fixes two types of MSVC compiler warnings.
- One parameter in the function signatures of two WGI event handlers had one level of indirection too much (and did not match Windows SDK headers). The indirection was cast away so it still worked.
- size_t was implicitly cast to UINT32 for a number of (constant) string lengths.
wahil1976
This patch adds the KBIO text input driver for FreeBSD, which allows text input to fully work without text spilling out into the console. It also supports accented input, AltGr keys and Alt Lock combinations.
Tested with US accent keys layout and various AltGr layouts.
This improves SDL's ability to detect joystick hotplug in a container
environment.
We cannot reliably receive events from udev in a container, because they
are delivered as netlink events, which are authenticated by their uid
being 0. However, in a user namespace created by an unprivileged user
(for example bubblewrap, as used by Flatpak and Steam's
pressure-vessel-wrap), the kernel does not allow us to map uid 0, and
the netlink events appear to be from the kernel's overflowuid (typically
65534/nobody), meaning libudev cannot distinguish between genuine uevents
from udevd and an attack by a malicious local user.
Signed-off-by: Simon McVittie <smcv@collabora.com>
Anything with X, Y and Z axes but no buttons is probably an
accelerometer (this is the assumption made in udev).
Signed-off-by: Simon McVittie <smcv@collabora.com>
Previously we only checked for at least one button or key and at least
the X and Y absolute axes, but this has both false positives and false
negatives.
Graphics tablets, trackpads and touchscreens all have buttons and
absolute X and Y axes, but we don't want to detect those as joysticks.
On normal Linux systems ordinary users do not have access to these
device nodes, but members of the 'input' group do.
Conversely, some game controllers only have digital buttons and no
analogue axes (the Nintendo Wiimote is an example), and some have axes
and no buttons (steering wheels or flight simulator rudders might not
have buttons).
Use the more elaborate heuristic factored out from SDL's udev code path
to handle these cases.
In an ideal world we could use exactly the same heuristic as udev's
input_id builtin, but that isn't under a suitable license for inclusion
in SDL, so we have to use a parallel implementation of something
vaguely similar.
Signed-off-by: Simon McVittie <smcv@collabora.com>
This works on capability bitfields that can either come from udev or
from ioctls, so it is equally applicable to both udev and non-udev
input device detection.
Signed-off-by: Simon McVittie <smcv@collabora.com>
Device enumeration via libudev can fail in a container for two reasons:
* the netlink protocol between udevd and libudev is considered private,
so there is no API guarantee that the version of libudev in a container
will understand netlink messages from a dissimilar version of udevd
on the host system;
* the netlink protocol between udevd and libudev relies for security on
being able to check the uid of each message, but in a container with
a user namespace where host uid 0 is not mapped, the libudev client
cannot distinguish between messages from host uid 0 and messages from
a different, malicious user on the host
To make this easier to experiment with, always compile the fallback
code path even if libudev is disabled. libudev remains the default if
enabled at compile time, but the fallback code path can be forced.
Signed-off-by: Simon McVittie <smcv@collabora.com>
GetAsyncKeyState() and GetRawInputData() report the state of the physical
buttons without applying the user's primary/secondary mouse button swap
preference. Swap the buttons returned from these functions, so we expose a
consistent view of the buttons to SDL callers. This new behavior also matches
the behavior of macOS and X11 backends.
See the Remarks section of the GetAsyncKeyState() function on MSDN.
We should only perform the VK_LEFT, VK_UP, etc. mapping if none of the other
special mappings apply. This allows the scancode normalization for the number
pad to take place as intended.
When we request realtime priority from rtkit, we have a rttime limit. If we exceed
that limit, the kernel will send SIGKILL to the process to terminate it.
This isn't something that most high priority processes will want, only processes
that selectively opt into SCHED_RR/FIFO through SDL_HINT_THREAD_PRIORITY_POLICY
should be subject to this level of scrutiny.
This change:
* Switches non-apple posix OSs to use SCHED_OTHER instead of SCHED_RR
for SDL_THREAD_PRIORITY_HIGH/SDL_THREAD_PRIORITY_TIME_CRITICAL.
* Fixes using a hardcoded RLIMIT_RTTIME, instead queries it from rtkit
* Only sets RLIMIT_RTTIME for MakeRealtime rtkit requests
* Adds a note regarding the possible SIGKILL with SDL_HINT_THREAD_PRIORITY_POLICY
* Introduces SDL_HINT_THREAD_FORCE_REALTIME_TIME_CRITICAL to allow apps to acquire realtime scheduling policies on Linux
CPU Vendor ID "Shanghai" and "CentaurHauls" belongs to Zhaoxin.
Background:
Shanghai Zhaoxin Semiconductor Co., Ltd ("Zhaoxin") , established in 2013,
headquartered in Zhangjiang, Shanghai, China. Zhaoxin aims at providing
general-purpose x86 processors.
Related Zhaoxin Linux Kernel patch can be found at
https://lore.kernel.org/lkml/01042674b2f741b2aed1f797359bdffb@zhaoxin.com
Best regards.
Debugging inside rtkit showed we were failing the RLIMIT_RTTIME check, now that we're asking for realtime and not just high-priority due to a change in SDL.
Between that and the DBus code in SDL being wrong in previous changelist I'm not sure how this could have ever worked.
Nov 02 20:34:15 redcore rtkit-daemon[2825]: Failed to parse MakeThreadRealtime() method call: Argument 1 is specified to be of type "uint32", but is actually of type "int32"
Nov 02 20:34:15 redcore rtkit-daemon[2825]: Failed to parse MakeThreadRealtime() method call: Argument 1 is specified to be of type "uint32", but is actually of type "int32"
Docs:
http://git.0pointer.net/rtkit.git/tree/README
CLIENTS:
To be able to make use of realtime scheduling clients may
request so with a small D-Bus interface that is accessible on
the interface org.freedesktop.RealtimeKit1 as object
/org/freedesktop/RealtimeKit1 on the service
org.freedesktop.RealtimeKit1:
void MakeThreadRealtime(u64 thread_id, u32 priority);
void MakeThreadHighPriority(u64 thread_id, s32 priority);
wcodelyokoyt
The atom name that X11_GetAtomName() returns never gets freed, which result in a minor memory leak (14 bytes?) every time the user drops a file on a window.
You can see the line in question here:
6b6170caf6/src/video/x11/SDL_x11events.c (L1350)
Fix: call XFree on name after the while loop.
Joel Linn
This patch fixes a MSVC warning, which is dependent on the regional settings of the build system. Although the character is inside a comment and harmless, it is undesirable to disable the warning for this.
OpenGL leaves the final line segment open, SDL's software renderer does not,
so we need a tiny bit of trigonometry here to move one more pixel in the right
direction.
Xbox Elite controllers use AUX1-AUX4 to represent the paddle buttons when using the HIDAPI driver
PS4 and PS5 controllers use AUX1 to represent the touchpad button
Nintendo Switch Pro controllers use AUX1 to represent the capture button
This allows one to build Raspberry Pi versions on an ancient version of
Raspbian and get both the KMSDRM and RPI video targets built into SDL, giving
maximum binary compatibility from linking against an older glibc, etc, but
also making one library that can access video on all RPi models and OS
releases.
batyastudios
Basicly there is problem and somewhat a solution: https://discourse.libsdl.org/t/setwindowmaximumsize-bug/28267
If you SDL_SetWindowMaximumSize() after SDL_SetWindowMinimumSize() with one of axes have the same value, function will have no effect.
This: (line 2144@SDL_video.c)
if (max_w <= window->min_w || max_h <= window->min_h) {
SDL_SetError("SDL_SetWindowMaximumSize(): Tried to set maximum size smaller than minimum size");
return;
}
May be changed to this:
if (max_w < window->min_w || max_h < window->min_h) {
SDL_SetError("SDL_SetWindowMaximumSize(): Tried to set maximum size smaller than minimum size");
return;
}
When converting audio from signed to unsigned values of vice-versa
the silence value chosen by SDL was the value of the device, not
of the stream that the data was being put into. After conversion
this would lead to a very high or low value, making the speaker
jump to a extreme positon, leading to an audible noise whenever
creating, destroying or playing scilence on a device that reqired
such conversion.
UnmapNotify event does not mean that window has been iconified. It
just reports that window changed state from mapped to unmapped.
XReparentWindow can unmap and remap window if it was mapped. This
causes unnecessary events - HIDDEN, MINIMIZED, RESTORED and SHOW.
These events are problematic with Metacity 3.36+ which started to
remove window decorations from fullscreen windows.
- SDL makes decorated window fullscreen
- Metacity removes decorations
- SDL gets UnmapNotify and exits from fullscreen
- Metacity re-adds decorations
As SDL will also get MapNotify event it will try to restore
window state causing above steps to repeat.
https://bugzilla.libsdl.org/show_bug.cgi?id=5314
Add a minimal my_gradd.h containing structures and constants only used
by SDL_os2vman.c -- based on public knowledge from around the internet
including pages from http://www.osfree.org and http://www.edm2.com .
Original code assigned MCIMixSetup.ulSamplesPerSec value to it, but it
is just the freq... We now change spec->samples only either if it is 0
or we changed the frequency, by picking a default of ~46 ms at desired
frequency (code taken from SDL_audio.c:prepare_audiospec()).
With this, the crashes I have been experiencing are gone.
- video: VideoBootStrap->available() is gone.
- thread: all important SDL_CreateThread internal data now put into
struct SDL_Thread: changes to SDL_SYS_CreateThread().
- events / video: SDL_SetDoubleClickTime() removed -- functionality
moved to SDL_mouse.c:SDL_MouseDoubleClickTimeChanged().
- video: struct SDL_VideoDevice-> CreateWindow and CreateWindowFrom
members renamed to CreateSDLWindow and CreateSDLWindowFrom
Has been happening with testfilesystem from 2.0.6 and newer because
of commit 572a721879ef.
Also set error strings in certain error conditions.
Also applied coding style / whitespace fixes, while I was there.