I Use This!
Activity Not Available

News

Analyzed about 1 month ago. based on code collected 4 months ago.
Posted 2 months ago
It’s almost the end of the year, so it’s time for a recap of the previous episodes, I guess. The tl;dr of 2018: started pretty much the same; massive dip in the middle; and, finally, got better at the very end. The first couple of months of the year ... [More] were pretty good; had a good time at the GTK hackfest and FOSDEM, and went to the Recipes hackfest in Yogyakarta in February. In March, my wife Marta was diagnosed with breast cancer; Marta already had (different types of) cancer twice in her life, and had been in full remission for a couple of years, which meant she was able to cope with the mechanics of the process, but it was still a solid blow. Since she had already gone through a round of radiotheraphy 20 years ago—which had likely a hand in the cancer appearing now—her only option was surgery to remove the whole breast tissue and the associated lymph nodes. Not fun, but surgery went well, and she didn’t even need chemotherapy, so all in all it could have been way, way worse. While Marta and I were dealing with that, I suddenly found myself out of a job, after working five years at Endless. To be fair, this left me with enough time to help out Marta while she was recovering—which is why I didn’t come to GUADEC. After Marta was back on her feet, and was able to raise her right arm above her head, I took the first vacation in, I think, about four years. I relaxed, read a bunch of books, played some video games, built many, many, many Gundam plastic models, recharged my batteries—and ended up finally having time to spend on a project that I had pushed back for a while, because I really needed to add writing and producing 15 to 20 minutes of audio every week, after perusing thousands of email archives and old web pages on the Wayback Machine. Side note: donate to the Wayback Machine, if you can. They provide a fundamental service for everybody using the Web, and especially for people like me who want to trace the history of things that happen on the Web. Of course I couldn’t stay home playing video games, recording podcasts, and building gunplas forever, and so I had to figure out where to go to work next, as I do enjoy being able to have a roof above my head, as well as buying food and stuff. By a crazy random happenstance, the GNOME Foundation announced that, thanks to a generous anonymous donation, it would start hiring staff, and that one of the open positions was for a GTK developer. I decided to apply, as, let’s be honest, it’s basically the dream job for me. I’ve been contributing to GNOME components for about 15 years, and to GTK for 12; and while I’ve been paid to contribute to some GNOME-related projects over the years, it was always as part of non-GNOME related work. The hiring process was really thorough, but in the end I managed to land the most amazing job I could possibly hope for. If you’re wondering what I’ll be working on, here’s a rough list: improving performance, especially on less powerful devices identify and land new features identify and fix pain points for current consumers of GTK On top of that, I’ll try to do my best to increase the awareness of the work being done on both the GTK 3.x stable branch, and the 4.x development branch, so expect more content appearing on the development blog. The overall idea is to ensure that GTK gets more exposure and mindshare in the next 5 years as the main toolkit for Linux and Unix-like operating systems, as well better functionality for application developers that want to make sure their projects work on other platforms. Finally, we want to make sure that more people feel confident enough to contribute to the core application development platform; if you have your pet feature or your pet bug inside GTK, and you want guidance, feel free to reach out to me. Hopefully, the next year will not look like this one, and will be a bit better. Of course, if we in the UK don’t all die in the fiery chaos that is the Brexit circus… [Less]
Posted 2 months ago by nore...@blogger.com (Bastien Nocera)
libfprint, the fingerprint reader driver library, is nearing a 1.0 release.Since the last time I reported on the status of the library, we've made some headway modernising the library, using a variety of different tools. Let's go through them and ... [More] how they were used.CallcatcherWhen libfprint was in its infancy, Daniel Drake found the NBIS fingerprint processing library matched what was required to provide fingerprint matching algorithms, and imported it in libfprint. Since then, the code in this copy-paste library in libfprint stayed the same. When updating it to the latest available version (from 2015 rather than 2007), as well as splitting off a patch to make it easier to update the library again in the future, I used Callcatcher to cull the unused functions.Callcatcher is not a "production-level" tool (too many false positives, lack of support for many common architectures, etc.), but coupled with manual checking, it allowed us to greatly reduce the number of functions in our copy, so they weren't reported when using other source code quality checking tools.LLVM's scan-buildThis is a particularly easy one to use as its use is integrated into meson, and available through ninja scan-build. The output of the tool, whether on stderr, or on the HTML pages, is pretty similar to Coverity's, but the tool is free, and easily integrated into a CI (once you've fixed all the bugs, obviously). We found plenty of possible memory leaks and unintialised variables using this, with more flexibility than using Coverity's web interface, and avoiding going through hoops when using its "source code check as a service" model.cflow and callgraphLLVM has another tool, called callgraph. It's not yet integrated into meson, which was a bit of a problem to get some output out of it. But combined with cflow, we used it to find where certain functions were called, trying to find the origin of some variables (whether they were internal or device-provided for example), which helped with implementing additional guards and assertions in some parts of the library, in particular inside the NBIS sub-directory.0.99.0 is outWe're not yet completely done with the first pass at modernising libfprint and its ecosystem, but we released an early Yule present with version 0.99.0. It will be integrated into Fedora after the holidays if the early testing goes according to plan.We also expect a great deal from our internal driver API reference. If you have a fingerprint reader that's unsupported, contact your laptop manufacturer about them providing a Linux driver for it and point them at this documentation.A number of laptop vendors are already asking their OEM manufacturers to provide drivers to be merged upstream, but a little nudge probably won't hurt.Happy holidays to you all, and see you for some more interesting features in the new year. [Less]
Posted 2 months ago by nore...@blogger.com (Robert Ancell)
I recently took a deep dive into the GIF format. In the process I learnt a few things by reading the specification. A GIF is made up of multiple images   I thought the GIF format would just contain a set of pixels. In fact, a GIF is made up of ... [More] multiple images. So a simple example like:  Could actually be made up of multiple images like this:   GIF has transparency, but that doesn't mean you have transparent GIFs  In the above example the sun and house images have the background in them. If the background was very detailed then this would be inefficient. So instead you can set a transparent colour index for each image. Pixels with this index don't replace the background pixels when the images are composited together. That's the only transparency in the specification. The background colour is actually encoded in the file so technically a GIF picture has all pixels set to a colour. However at some point renderers decided they wanted transparency and ignored the background colour and set it to transparent instead. It's not in the spec, but it's what everyone does. This is the reason that GIF transparency looks bad - there's no alpha channel, just a hack abusing another feature.You can have more than 256 colours  GIFs are well known for having a palette of only up to 256 colours. However, you can have a different palette for each image in the GIF. That means in the above example you could use a palette with lots of greens and blues for the background, lots of reds for the house and lots of yellows for the sun. The combined image could have up to 768 colours! With some clever encoding you can have a GIF file that uses up to 24 million colours.Animation is just delaying the rendering  GIFs are most commonly used for small animations. This wasn't in the original specification but at some point someone realised if you inserted a delay between each image you could make an animation! In the above example we could animate by adding more images of the sun that were rotated from the previous frame with a delay before them:   Why we can't have nice things With all of the above GIF is both a simple but powerful format. You can make an animation that is made up of small updates efficiently encoded.Sadly however someone decided that all images inside a GIF file should be treated as animation frames. And they should have a minimum delay time (including zero delays being rounded up to 20ms or so). So if you want you GIF to look as you intended you're stuck with one image per frame and only 256 colours per frame unless the common decoders are fixed. It seems the main reason they continue to be like this is there are badly encoded GIF files online and they don't want them to stop working.GIF, you are a surprisingly beautiful format and it's a shame we don't see your full potential! [Less]
Posted 2 months ago by nore...@blogger.com (Robert Ancell)
Here is the story of how I fell down a rabbit hole and ended up learning far more about the GIF image format than I ever expected... We had a problem with users viewing a promoted snap using GNOME Software. When they opened the details page ... [More] they'd have huge CPU and memory usage. Watching the GIF in Firefox didn't show a problem - it showed a fairly simple screencast demoing the app without any issues. I had a look at the GIF file and determined: It was quite large for a GIF (13Mb). It had a lot of frames (625). It was quite high resolution (1790×1060 pixels). It appeared the GIF was generated from a compressed video stream, so most of the frame data was just compression artifacts. GIF is lossless so it was faithfully reproducing details you could barely notice. GNOME Software uses GTK+, which uses gdk-pixbuf to render images. So I had a look a the GIF loading code. It turns out that all the frames are loaded into memory. That comes to 625×1790×1060×4 bytes. OK, that's about 4.4Gb... I think I see where the problem is. There's a nice comment in the gdk-pixbuf source that sums up the situation well:  /* The below reflects the "use hell of a lot of RAM" philosophy of coding */ They weren't kidding. 🙂 While this particular example is hopefully not the normal case the GIF format has has somewhat come back from the dead in recent years to be a popular format. So it would be nice if gdk-pixbuf could handle these cases well. This was going to be a fairly major change to make. The first step in refactoring is making sure you aren't going to break any existing behaviour when you make changes. To do this the code being refactored should have comprehensive tests around it to detect any breakages. There are a good number of GIF tests currently in gdk-pixbuf, but they are mostly around ensuring particular bugs don't regress rather than checking all cases. I went looking for a GIF test suite that we could use, but what was out there was mostly just collections of GIFs people had made over the years. This would give some good real world examples but no certainty that all cases were covered or why you code was breaking if a test failed. If you can't find what you want, you have to build it. So I wrote PyGIF - a library to generate and decode GIF files and made sure it had a full test suite. I was pleasantly surprised that GIF actually has a very well written specification, and so implementation was not too hard. Diversion done, it was time to get back to gdk-pixbuf. Tests plugged in, and the existing code actually has a number of issues. I fixed them, but this took a lot of sanity to do so. It would have been easier to replace the code with new code that met the test suite, but I wanted the patches to be back-portable to stable releases (i.e. Ubuntu 16.04 and 18.04 LTS). And with a better foundation, I could now make GIF frames load on demand. May you GIF viewing in GNOME continue to be awesome. [Less]
Posted 2 months ago
Introduction For this very first round of GNOME Internships I’ll work in the USB Protection project. The attack surface of USB is quite large and while disabling USB altogether solves the problem, it creates other. As do existing protection ... [More] mechanisms. They suffer from poor usability and missing integration into the operating system. This is why here we are trying a different approach to defend against rogue USB devices for a GNOME-based operating system. USB is arguably to most exposed interface of a user’s machine. It allows an attacker to interact with pretty much any driver, many of which are of questionable quality. In order to protect the users, while keeping the entire system easy to use, we try to be smart about when to allow new USB devices. First, we try to detect when the user is present, arguing that if the user is not then new USB devices should not work. But even this apparently simple case can hide some complications, because for example you might very well want to attach a new keyboard in case yours breaks. Keyboards, however, pose another risk as several attacks have shown. This project will be handled with an incremental build model, decomposing the whole problem in parts. In this way we’ll be able to start tackling the problem from the easier cases and gradually increase the proposed solution complexity. USBGuard In this “preparation” month I started to look into USBGuard, because it is very likely that this will be the component we will use within GNOME in order to protect the USB ports. The configuration of USBGuard consists of two files: usbguard-daemon.conf and rules.conf. The former holds a few variables like InsertedDevicePolicy and ImplicitPolicyTarget, while the latter is a file where it’s possible to whitelist/blacklist single, or groups of, USB devices. When you plug in a new USB device in your system, USBGuard performs a few sequential checks in order to decide if a device should be enabled: From the usbguard-daemon.conf the value of InsertedDevicePolicy will be checked: If it is apply-policy it will go to the step 2. If it is block or reject the device will be, respectively, deauthorized or removed. No further checks will be performed. The rules.conf file will be parsed: If there is a rule that matches the inserted USB device it will be applied. No further checks will be performed. Otherwise it will go to the step 3. From the usbguard-daemon.conf the value of ImplicitPolicyTarget will be checked: If it is allow the device will be authorized If it is block or reject the device will be, respectively, deauthorized or removed. On top of that, from the CLI/DBus there is a function called applyDevicePolicy that can be used to override the decision that USBGuard took after the three steps listed above. In applyDevicePolicy there is a parameter called permanent. If it is set to False the policy override will just work as long as the device stays plugged in. Otherwise if set to True, the policy will be stored in the rules.conf file. USBGuard limitations USBGuard configuration can be accessed and manipulated with DBus. Unfortunately there were two major deal breaker for us: There were no signals when a parameter were changed. In this way requiring a polling for getting the current updated configuration values. From DBus it was possible to get and set only the InsertedDevicePolicy parameter. The first issue was solved with this PR, now already merged in master. The second is an issue for us because without being able to manipulate ImplicitPolicyTarget we can’t, for example, easily reach a state where we allow every new USB devices. Regarding this limitation I proposed a fix with this PR, and it is currently waiting for approval. Work done so far My starting point was regarding the first step where we display an entry in GNOME Control Center under the Privacy tab that let the user permanently allow or disallow new USB devices. So far I created two proof of concepts of this functionality: The first uses a GSettings entry to store the chosen value. The second where the displayed value always reflects the InsertedDevicePolicy from the USBGuard configuration. For the second step the plan was to give an option to forbid new USB devices only when the lock screen was active. This can be considered a sort of a middle ground between the permanently allow and disallow. So far I did a first proof of concept where I displayed a drop down menu letting the users choose between “always”, “never” and “when lock screen is active”. The chosen property is then propagated to the USBGuard configuration and also stored with GSettings. What to expect in the following 1-2 weeks Currently in the PoC that I realized I’m working exclusively with the InsertedDevicePolicy property. While this is good enough when we want to block USB devices, it is subpar when we want to deactivate the protection. The only way to be 100% sure that every new devices will be allowed is with ImplicitPolicyTarget. As soon as we will be able to control it too, I’ll adjust my implementation accordingly. In the meantime I can prepend a wildcard “allow” to the rule file to achieve the same result. I also need to improve the USBGuard check, in order to better inform the users if something is not working as expected (e.g. too old version of USBGuard or wrong initial USBGuard configuration). Regarding the second step I’ll create a patch for GNOME Shell that binds the USB locking logic to the lock screen process and, before acting, it checks the stored property from GNOME Control Center to decide how to behave based on the users choice. In this step also an interesting question raises: What to do with devices which have been inserted while the lock screen was on? Initially we probably keep them blocked and maybe we should show a notification about them to inform the users that they need to be re-plugged to make them work. Thanks I’d like to thanks Tobias Muller for guiding me in this project and the whole GNOME foundation for this awesome opportunity. [Less]
Posted 2 months ago
If you missed it, the introduction to this project can be found here. Check if we are in a working state Before letting the user select the desired level of USB protection, we check if we are in a working state. Meaning for example that USBGuard ... [More] needs to be installed and the corresponding DBus service needs to be active. If these conditions are not met, we grey out the dropdown menu in GNOME-Control-Center. This method probably can be improved showing also the reason of the non working state to the users. “allow” wildcard rule As I mentioned in my previous blog post, we can’t get or set ImplicitPolicyTarget from the USBGuard configuration. While the PR is still open, we worked around this issue using the rule file. Prepending a wildcard allow rule allow *:* we are now able to reach a state where every new inserted devices are automatically allowed. It works like this: If you set the protection level to Never, GNOME-Control-Center (g-c-c) sets InsertedDevicePolicy to apply-policy and add at the beginning of the rule file allow *:*. In this way when a new USB device is plugged: USBGuard checks InsertedDevicePolicy. Because it is set to apply-policy it goes to the step 2. USBGuard checks the rule file for a matching rule. allow *:* matches, and so the device gets authorized to work. If you set the protection level to Always, g-c-c sets InsertedDevicePolicy to block. When a new USB device is plugged: USBGuard checks InsertedDevicePolicy. Because it is set to block the device gets blocked without checking the rule file. Fail-safe mode Using the allow wildcard is also useful for reaching a fail-safe mode when we want USB protection when the lock screen is active. What does fail-safe mean? Let me give you a real world example: The user sets the USB protection level to “when lock screen is active”, so when the session is unlocked he can freely plug in USB devices. But when the session gets locked all new USB devices needs to be blocked. The logic here is bounded in GNOME-Shell’s lock and unlock functions. When a lock happens we set InsertedDevicePolicy to block. When the session is unlocked we set InsertedDevicePolicy to apply-policy. But what happen if the user activates the lock screen and then GNOME-Shell crashes? After a reboot InsertedDevicePolicy will continue to be at block, so is the user locked out? No because there is a trick. When USBGuard service starts there is another config variable that gets checked: PresentDevicePolicy. This rule regulates how to handle already connected USB devices. By default it is set to apply-policy, meaning that it will check the rule files and, if there isn’t a match, the ImplicitPolicyTarget value. And because we have an allow *:* in our rule file, already present devices will get authorized. Oof, there is a lot in this section. But there is one last thing. Ok, we are not locked out because we can still use our plugged in, at boot time, USB devices, great. But what about InsertedDevicePolicy? It is stuck to block while it should be at apply-policy, how we reset it now? If you end up in this situation, you can invoke the lock screen one single time and everything will return as it should. Reflect manual user changes USBGuard can now be configured from GNOME-Control-Center, awesome. But what happens if I set something from g-c-c and later I manually edit the USBGuard configuration within the CLI or DBus? In order to reflect the current USBGuard status we subscribe to the new PropertyParameterChanged signal. If the protection level was “Always” but InsertedDevicePolicy gets changed to apply-policy, or also the other way around, if the protection level was “Never” but InsertedDevicePolicy gets changed to block, it’s save to assume that the user manually changed the USBGuard configuration. So we change the displayed value accordingly (without further changing the current USBGuard config values). Notification for blocked USB devices If a new USB device has been blocked because plugged in when the session was locked, we display a notification to inform the user that he needs to replug his device. Step 3 - From static to dynamic Until now everything has been achieved with a “static” configuration of USBGuard. That means that we edited USBGuard in order to let it do what we wanted, but we were not actively listening to USBGuard events, like to the signal DevicePrecenceChanged. With this static configuration we probably can’t do much else, we reached the capability limit. This is the reason why now everything has been switched to be more dynamic. Now the new GNOME-Shell’s USB component, similarly to the Thunderbolt one, actively listens to USBGuard signals and act accordingly. What to expect next and comments The two major things to expect are: smarter way to handle keyboards even if the protection is active (what happens if my keyboard breaks?) and also trying to add some sort of protection even when the session is unlocked (improving in this way the “block all” that we have right now). Feedback is welcome! [Less]
Posted 2 months ago
First two days of work The Tuesday 11th started the second Fractal Hackfest. I've organized this hackfest in Seville, the city where I studied computer science and here I've a lot of friends in the University so is a good place to do it here. The ... [More] weather was important too for the hackfest selection, in December Seville is a good choice because the weather is not too cold, we're having sunny days. The first day was a good day, thinking about some relevant issues and planning what we want to do. We talked about the work needed for the interface split, about the E2EE support, new features and the need for a new release. We're having some problems with the internet connection, because the University has a restricted network policy and we ask for the guess internet connection the Monday, but we're still waiting. Meantime we have to thanks to Julian Sparber the hackfest wifi, because he's using his laptop to stream the eduroam connection. Newcomers The first day we try to promote as a newcomers day, and some people comes. We've some contributions and I spend some time trying to help people to introduce to the GNOME community. GNOME Foundation sponsored dinner The GNOME Foundation payed for a Fractal dev day dinner, so we should thanks this great dinner to GNOME: We've a good time eating and drinking in the Coco Verde. We talk about GNOME, the desktop, matrix.org and other communication tools. Hacking day Today was a hacking day, so we started to work in the stuff that we talk about yesterday. We've resolved some minor issues and I started with the fractal-backend crate. We talked about move all the app data model and logic to the fractal-backend and leave fractal-gtk only as UI management. We talked about the LMDB use to store rooms and messages and we decided that the best solution should be to use a relational database, because we've relations and with the key-value thing we'll end creating those relations and maintaining by hand. In any case, I've this decision in mind and I'm implementing all this with a trait to hide the storage detail so we can change easily in the future. So today I've spend a lot of time implementing this trait and a first implementation for the Room struct. I've decided to use rusqlite instead the diesel orm because I want to keep it simple. I want to finish all the database storage and move the AppOp main loop to the fractal-backend and try to update the fractal-gtk to use the backend instead the AppOp struct to get the rooms and messages. But maybe is a lot of work, I don't know if I'll be able to finish this before the end of the hackfest. Thanks This hackfest is possible because there's a lot of volunteer work and people helping us. First of all, the Fractal core team that comes Tobias Bernard, Julian Sparber and Alexandre Franke and of course the GNOME Foundation. And also we've to thank Alejandro Domínguez, a newcomer that is doing a really good job fixing bugs and cleaning some old code. Then I want to thank the Linux local group, SUGUS for the help and also I want to thank to other free software related group Plan4D. Plan4D is giving us some help with the place and cookies, fruits, juices and some tea. And finally I want to thank again to my coworkers in wadobo because they support me to spend a full work week working in gnome and they also spend some time helping us to organize all the hackfest stuff. [Less]
Posted 2 months ago by nore...@blogger.com (Peter Hutterer)
Disclaimer: this is pending for v4.21 and thus not yet in any kernel release. Most wheel mice have a physical feature to stop the wheel from spinning freely. That feature is called detents, notches, wheel clicks, stops, or something like that. On ... [More] your average mouse that is 24 wheel clicks per full rotation, resulting in the wheel rotating by 15 degrees before its motion is arrested. On some other mice that angle is 18 degrees, so you get 20 clicks per full rotation. Of course, the world wouldn't be complete without fancy hardware features. Over the last 10 or so years devices have added free-wheeling scroll wheels or scroll wheels without distinct stops. In many cases wheel behaviour can be configured on the device, e.g. with Logitech's HID++ protocol. A few weeks back, Harry Cutts from the chromium team sent patches to enable Logitech high-resolution wheel scrolling in the kernel. Succinctly, these patches added another axis next to the existing REL_WHEEL named REL_WHEEL_HI_RES. Where available, the latter axis would provide finer-grained scroll information than the click-by-click REL_WHEEL. At the same time I accidentally stumbled across the documentation for the HID Resolution Multiplier Feature. A few patch revisions later and we now have everything queued up for v4.21. Below is a summary of the new behaviour. The kernel will continue to provide REL_WHEEL as axis for "wheel clicks", just as before. This axis provides the logical wheel clicks, (almost) nothing changes here. In addition, a REL_WHEEL_HI_RES axis is available which allows for finer-grained resolution. On this axis, the magic value 120 represents one logical traditional wheel click but a device may send a fraction of 120 for a smaller motion. Userspace can either accumulate the values until it hits a full 120 for one wheel click or it can scroll by a few pixels on each event for a smoother experience. The same principle is applied to REL_HWHEEL and REL_HWHEEL_HI_RES for horizontal scroll wheels (which these days is just tilting the wheel). The REL_WHEEL axis is now emulated by the kernel and simply sent out whenever we have accumulated 120. Important to note: REL_WHEEL and REL_HWHEEL are now legacy axes and should be ignored by code handling the respective high-resolution version. The magic value of 120 is taken directly from Windows. That value was chosen because it has a good number of integer factors, so dividing 120 by whatever multiplier the mouse uses gives you a integer fraction of 120. And because HW manufacturers want it to work on Windows, we can rely on them doing it right, provided we use the same approach. There are two implementations that matter. Harry's patches enable the high-resolution scrolling on Logitech mice which seem to mostly have a multiplier of 8 (i.e. REL_WHEEL_HI_RES will send eight events with a value of 15 before REL_WHEEL sends 1 click). There are some interesting side-effects with e.g. the MX Anywhere 2S. In high-resolution mode with a multiplier of 8, a single wheel movement does not always give us 8 events, the firmware does its own magic here. So we have some emulation code in place with the goal of making the REL_WHEEL event happen on the mid-point of a wheel click motion. The exact point can shift a bit when the device sends 7 events instead of 8 so we have a few extra bits in place to reset after timeouts and direction changes to make sure the wheel behaviour is as consistent as possible. The second implementation is for the generic HID protocol. This was all added for Windows Vista, so we're only about a decade behind here. Microsoft got the Resolution Multiplier feature into the official HID documentation (possibly in the hope that other HW manufacturers implement it which afaict didn't happen). This feature effectively provides a fixed value multiplier that the device applies in hardware when enabled. It's basically the same as the Logitech one except it's set through a HID feature instead of a vendor-specific protocol. On the devices tested so far (all Microsoft mice because no-one else seems to implement this) the multipliers vary a bit, ranging from 4 to 12. And the exact behaviour varies too. One mouse behaves correctly (Microsoft Comfort Optical Mouse 3000) and sends more events than before. Other mice just send the multiplied value instead of the normal value, so nothing really changes. And at least one mouse (Microsoft Sculpt Ergonomic) sends the tilt-wheel values more frequently and with a higher value. So instead of one event with value 1 every X ms, we now get an event with value 3 every X/4 ms. The mice tested do not drop events like the Logitech mice do, so we don't need fancy emulation code here. Either way, we map this into the 120 range correctly now, so userspace gets to benefit. As mentioned above, the Resolution Multiplier HID feature was introduced for Windows Vista which is... not the most recent release. I have a strong suspicion that Microsoft dumped this feature as well, the most recent set of mice I have access to don't provide the feature anymore (they have vendor-private protocols that we don't know about instead). So the takeaway for all this is: if you have a Logitech mouse, you'll get higher-resolution scrolling on v4.21. If you have a Microsoft mouse a few years old, you may get high-resolution wheel scrolling if the device supports it. Any other vendor or a new Microsoft mouse, you don't get it. Coincidentally, if you know anyone at Microsoft who can provide me with the specs for their custom protocol, I'd appreciate it. We'd love to have support for it both in libratbag and in the kernel. Or any other vendor, come to think of it. [Less]
Posted 2 months ago by nore...@blogger.com (Marcus Lundblad)
It´s been ages since I last shared any Maps news, so it´s probably about time…Some things have happened since the stable 3.30.0 release in September.First off we have a new application icon, courtesy of Jakub Steiner using the icon style for the ... [More] upcoming GNOME 3.32Furthermore the application menu has moved into the new “hamburger menu ” in the title bar, in-line with changes being carried out across the board for GNOME applications, since the adoption of the desktop top bar menu for application-wide action was never really adopted in any significance by third-party applications.Lately James Westman have made various valuable contributions, among others a better experience on first launch (should be no more gray areas “north of the north pole” in these situations), getting rid of some deprecation warnings when running with newer GJS versions, and also a bug fix with some parts from our C-based glue library for loading addresses from the contact book not being exposed as introspectable (and thus not being visible from JavaScript code) which strangely somehow was still working on older GJS. So I also made an additional bug-fix for the 3.30 series (3.30.3) with this fix.Another feature James has been working on is replacing our old thumbnails that was being used in the menu for selecting the map style. This has been using static graphics captured from our previous map tile provider (MapQuest) which are not only not in-line with the currenly used tile style but may also be in a legal grey-zone. So one idea I floated was to dynamically use content from the current map view for the thumbnails.James made some experimenting with this in WIP branch: We have not decided quite yet from a design perspective if we should go with this approach, but I think it looks and feels pretty sleek. One slight downside is that it generates some additional tile accesses, but I think it´s acceptable.So thank you very much James!That´s that for now, and all have happy holidays! [Less]
Posted 2 months ago by nore...@blogger.com (Peter Hutterer)
This time we're digging into HID - Human Interface Devices and more specifically the protocol your mouse, touchpad, joystick, keyboard, etc. use to talk to your computer. Remember the good old days where you had to install a custom driver for every ... [More] input device? Remember when PS/2 (the protocol) had to be extended to accommodate for mouse wheels, and then again for five button mice. And you had to select the right protocol to make it work. Yeah, me neither, I tend to suppress those memories because the world is awful enough as it is. As users we generally like devices to work out of the box. Hardware manufacturers generally like to add bits and bobs because otherwise who would buy that new device when last year's device looks identical. This difference in needs can only be solved by one superhero: Committee-man, with the superpower to survive endless meetings and get RFCs approved. Many many moons ago, when USB itself was in its infancy, Committee man and his sidekick Caffeine boy got the USB consortium agree on a standard for input devices that is so self-descriptive that operating systems (Win95!) can write one driver that can handle this year's device, and next year's, and so on. No need to install extra drivers, your device will just work out of the box. And so HID was born. This may only an approximate summary of history. Originally HID was designed to work over USB. But just like Shrek the technology world is obsessed with layers so these days HID works over different transport layers. HID over USB is what your mouse uses, HID over i2c may be what your touchpad uses. HID works over Bluetooth and it's celebrity-diet version BLE. Somewhere, someone out there is very slowly moving a mouse pointer by sending HID over carrier pigeons just to prove a point. Because there's always that one guy. HID is incredibly simple in that the static description of the device can just be bytes burnt into the ROM like the Australian sun into unprepared English backpackers. And the event frames are often an identical series of bytes where every bit is filled in by the firmware according to the axis/buttons/etc. HID is incredibly complicated because parsing it is a stack-based mental overload. Each individual protocol item is simple but getting it right and all into your head is tricky. Luckily, I'm here for you to make this simpler to understand or, failing that, at least more entertaining. As said above, the purpose of HID is to make devices describe themselves in a generic manner so that you can have a single driver handle any input device. The idea is that the host parses that standard protocol and knows exactly how the device will behave. This has worked out great, we only have around 200 files dealing with vendor- and hardware-specific HID quirks as of v4.20. HID messages are Reports. And to know what a Report means and how to interpret it, you need a Report Descriptor. That Report Descriptor is static and contains a series of bytes detailing "what" and "where", i.e. what a sequence of bits represents and where to find those bits in the Report. So let's try and parse one of Report Descriptors, let's say for a fictional mouse with a few buttons. How exciting, we're at the forefront of innovation here. The Report Descriptor consists of a bunch of Items. A parser reads the next Item, processes the information within and moves on. Items are small (1 byte header, 0-4 bytes payload) and generally only apply exactly one tiny little bit of information. You need to accumulate several items to build up enough information to actually know what's happening. The "what" question of the Report Descriptor is answered with the so-called Usage. This could be something simple like X or Y (0x30 and 0x31) or something more esoteric like System Menu Exit (0x88). A Usage is 16 bits but all Usages are grouped into so-called Usage Pages. A Usage Page too is a 16 bit value and together they form the 32-bit value that tells us what the device can do. Examples: 0001 0031 # Generic Desktop, Y 0001 0088 # Generic Desktop, System Menu Exit 0003 0005 # VR Controls, Head Tracker 0003 0006 # VR Controls, Head Mounted Display 0004 0031 # Keyboard, Keyboard \ and | Note how the Usage in the last item is the same as the first one, without the Usage Page you will mix things up. It helps if you always think of as the Usage as a 32-bit number. For your kids' bed-time story time, here are the HID Usage Tables from 2004 and the approved HID Usage Table Review Requests of the last decade. Because nothing puts them to sleep quicker than droning on about hex numbers associated with remote control buttons. To successfully interpret a Report from the device, you need to know which bits have which Usage associated with them. So let's go back to our innovative mouse. We would want a report descriptor with 6 items like this: Usage Page (Generic Desktop)Usage (X)Report Size (16)Usage Page (Generic Desktop)Usage (Y)Report Size (16)This basically tells the host: X and Y both have 16 bits. So if we get a 4-byte Report from the device, we know two bytes are for X, two for Y. HID was invented when a time when bits were more expensive than printer ink, so we can't afford to waste any bits (still the case because who would want to spend an extra penny on more ROM). HID makes use of so-called Global items, once those are set their value applies to all following items until changed. Usage Page and Report Size are such Global items, so the above report descriptor is really implemented like this: Usage Page (Generic Desktop)Usage (X)Usage (Y)Report Count (2)Report Size (16)Input (Data,Var,Rel)The Report Count just tells us that 2 fields of the current Report Size are coming up. We have two usages, two fields, and 16 bits each so we know what to do. The Input item is sort-of the marker for the end of the stack, it basically tells us "process what you've seen so far", together with a few flags. Rel in this case means that the Usages are relative. Oh, and Input means that this is data from device to host. Output would be data from host to device, e.g. to set LEDs on a keyboard. There's also Feature which indicates configurable items. Buttons on a device are generally just numbered so it'd be monumental 16-bits-at-a-time waste to have HID send Usage (Button1), Usage (Button2), etc. for every button on the device. HID instead provides a Usage Minimum and Usage Maximumto sequentially order them. This looks like this: Usage Page (Button)Usage Minimum (1)Usage Maximum (5)Report Count (5)Report Size (1)Input (Data,Var,Abs)So we have 5 buttons here and each button has one bit. Note how the buttons are Abs because a button state is not a relative value, it's either down or up. HID is quite intolerant to Schrödinger's thought experiments. Let's put the two things together and we have an almost-correct Report descriptor: Usage Page (Button)Usage Minimum (1)Usage Maximum (5)Report Count (5)Report Size (1)Input (Data,Var,Abs)Report Size (3)Report Count (1)Input (Cnst,Arr,Abs)Usage Page (Generic Desktop)Usage (X)Usage (Y)Report Count (2)Report Size (16)Input (Data,Var,Rel)New here is Cnst. This signals that the bits have a constant value, thus don't need a Usage and basically don't matter (haha. yeah, right. in theory). Linux does indeed ignore those. Cnst is used for padding to align on byte boundaries - 5 bits for buttons plus 3 bits padding make 8 bits. Which makes one byte as everyone agrees except for granddad over there in the corner. I don't know how he got in. Were we to get a 5-byte Report from the device, we'd parse it approximately like this: button_state = byte[0] & 0x1f x = bytes[1] | (byte[2] << 8) y = bytes[3] | (byte[4] << 8)Hooray, we're almost ready. Except not. We may need more info to correctly interpret the data within those reports. The Logical Minimum and Logical Maximum specify the value range of the actual data. We need this to tell us whether the data is signed and what the allowable range is. Together with the Physical Minimumand the Physical Maximum they specify what the values really mean. In the simple case: Usage Page (Generic Desktop)Usage (X)Usage (Y)Report Count (2)Report Size (16)Logical Minimum (-32767)Logical Maximum (32767)Input (Data,Var,Rel)This just means our x/y data is signed. Easy. But consider this combination: ...Logical Minimum (0)Logical Maximum (1)Physical Minimum (1)Physical Maximum (12)This means that if the bit is 0, the effective value is 1. If the bit is 1, the effective value is 12. Note that the above is one report only. Devices may have multiple Reports, indicated by the Report ID. So our Report Descriptor may look like this: Report ID (01)Usage Page (Button)Usage Minimum (1)Usage Maximum (5)Report Count (5)Report Size (1)Input (Data,Var,Abs)Report Size (3)Report Count (1)Input (Cnst,Arr,Abs)Report ID (02)Usage Page (Generic Desktop)Usage (X)Usage (Y)Report Count (2)Report Size (16)Input (Data,Var,Rel) If we were to get a Report now, we need to check byte 0 for the Report ID so we know what this is. i.e. our single-use hard-coded parser would look like this: if byte[0] == 0x01: button_state = byte[1] & 0x1f else if byte[0] == 0x02: x = bytes[2] | (byte[3] << 8) y = bytes[4] | (byte[5] << 8)A device may use multiple Reports if the hardware doesn't gather all data within the same hardware bits. Now, you may ask: if I get fifteen reports, how should I know what belongs together? Good question, and lucky for you the HID designers are miles ahead of you. Report IDs are grouped into Collections. Collections can have multiple types. An Application Collectiondescribes a set of inputs that make sense as a whole. Usually, every Report Descriptor must define at least one Application Collection but you may have two or more. For example, a a keyboard with integrated trackpoint should and/or would use two. This is how the kernel knows it needs to create two separate event nodes for the device. Application Collections have a few reserved Usages that indicate to the host what type of device this is. These are e.g. Mouse, Joystick, Consumer Control. If you ever wondered why you have a device named like "Logitech G500s Laser Gaming Mouse Consumer Control" this is the kernel simply appending the Application Collection's Usage to the device name. A Physical Collection indicates that the data is collected at one physical point though what a point is is a bit blurry. Theoretical physicists will disagree but a point can be "a mouse". So it's quite common for all reports on a mouse to be wrapped in one Physical Collections. If you have a device with two sets of sensors, you'd have two collections to illustrate which ones go together. Physical Collections also have reserved Usages like Pointer or Head Tracker. Finally, a Logical Collection just indicates that some bits of data belong together, whatever that means. The HID spec uses the example of buffer length field and buffer data but it's also common for all inputs from a mouse to be grouped together. A quick check of my mice here shows that Logitech doesn't wrap the data into a Logical Collection but Microsoft's firmware does. Because where would we be if we all did the same thing... Anyway. Now that we know about collections, let's look at a whole report descriptor as seen in the wild: Usage Page (Generic Desktop)Usage (Mouse)Collection (Application) Usage Page (Generic Desktop) Usage (Mouse) Collection (Logical) Report ID (26) Usage (Pointer) Collection (Physical) Usage Page (Button) Usage Minimum (1) Usage Maximum (5) Report Count (5) Report Size (1) Logical Minimum (0) Logical Maximum (1) Input (Data,Var,Abs) Report Size (3) Report Count (1) Input (Cnst,Arr,Abs) Usage Page (Generic Desktop) Usage (X) Usage (Y) Report Count (2) Report Size (16) Logical Minimum (-32767) Logical Maximum (32767) Input (Data,Var,Rel) Usage (Wheel) Physical Minimum (0) Physical Maximum (0) Report Count (1) Report Size (16) Logical Minimum (-32767) Logical Maximum (32767) Input (Data,Var,Rel) End Collection End CollectionEnd CollectionWe have one Application Collection (Generic Desktop, Mouse) that contains one Logical Collection (Generic Desktop, Mouse). That contains one Physical Collection (Generic Desktop, Pointer). Our actual Report (and we have only one but it has the decimal ID 26) has 5 buttons, two 16-bit axes (x and y) and finally another 16 bit axis for the Wheel. This device will thus send 8-byte reports and our parser will do: if byte[0] != 0x1a: # it's decimal in the above descriptor error, should be 26 button_state = byte[1] & 0x1f x = byte[2] | (byte[3] << 8) y = byte[4] | (byte[5] << 8) wheel = byte[6] | (byte[7] << 8)That's it. Now, obviously, you can't write a parser for every HID descriptor out there so your actual parsing code needs to be generic. The Linux kernel does exactly that and so does everything else that needs to parse HID. There's a huge variety in devices out there, all with HID descriptors that may or may not be correct. As with so much in life, correct HID implementations are often defined by "whatever Windows accepts" so if you like playing catch, Linux development is for you. Oh, in case you just got a bit too optimistic about the state of the world: HID allows for vendor-defined usages. Which does exactly what you'd think it does, it hides vendor-specific protocol inside what should be a generic protocol. There are devices with hidden report IDs that you can only unlock by sending the right magic sequence to the report and/or by defeating the boss on Level 4. Usually those devices present themselves as basic/normal devices over HID but if you know the magic sequence you get to use *gasp* all buttons. Or access the device-specific configuration features. Logitech's HID++ is just one example here but at least that's one where we have most of the specs available. The above describes how to parse the HID report descriptor and interpret the reports. But what happens once you have a HID report correctly parsed? In the case of the Linux kernel, once the report descriptor is parsed evdev nodes are created (one per Application Collection, more or less). As the Reports come in, they are mapped to evdev codes and the data appears on the evdev node. That's where userspace like libinput can pick it up. That bit is actually quite simple (mostly anyway). The above output was generated with the tools from the hid-tools repository. Go forth and hid-record. [Less]