-
[E1][C] Improved mouse smoothness
11/28/2023 at 00:06 • 0 commentsThis suprisingly took even more effort than the ButtonRing and I got a lot more help from BingChat this time around. Essentially, I wanted to replace the simple method with one that waited until it was sure both the real and imaginary components were accounted for. This is the plan I wrote just to have an idea on what to do:
I then asked BingChat many C++ questions, such as
I then started deriving equations in Desmos:
To get that slow movement zone, I needed to store the fractional part of the number I sent to SendMouse so that it could be carried forward.
Eventually, I had to create a massive wall of logs to debug:
I still had the issue with overshooting, so I had the idea to implement a bell curve that would multiply the output by considering the %-changed of the magnitude. Didn't help:
I went in, fixed a bug with the %-change calculation, and tried many different curves, namely those that actually went negative when the %-change was close to -100% as it would actually cause the mouse to bounce back slightly, mirroring the actual feeling on the spacemouse.
The finishing touch I've just added now are some lines so that the bounceback feature actually bounces back in the same direction it came in:
Before this change, I'd often have situations like this:
[9 Dec] I've mostly been using the below displacement multiplier curves (before admitting defeat and trying a Logitech G300s mouse):
For the multiplier when decelerating (-1 <= x <= 0), I just tried the 4 combinations of the 2 curves and got the most points in the accuracy test with the above configuration.
For accelerating, my reasoning was that I'd either be coasting (so near 0) or wanting to accelerate (usually over 14), thus values in the middle should be supressed as I'm probably just transitioning from one to the other. In practice, looking at the logs, it seems that change-in-magnitude readings are something like 20 -> 8 -> 2 -> 1.5 -> 0.8 -> 0.2..., so don't seem to be many values around in the suppression region anyway.
If I could just get the ergonomics of the SpaceExplorer with the speed and precision of the G300s, that would be great. Like the opposite version of the Wing mouse:
-
[C] Made ButtonRing diagonals consistent with cardinal directions
11/19/2023 at 19:59 • 0 commentsSomething I noticed when using the ButtonRing is that it seemed that less force was needed to press. This ment that I often activated the Diagonal Edge button instead of the Outer Diagonal button and it would take 4 - 5 attempts to get it right.
The reason is because diagonal magnitudes are able to be larger than cardinals.
When I first encountered the issue, I considered doing something inside the angle-checking if-blocks themselves, but I thought that would just result in a cliff-edge response between the main cardinal directions and the diagonal directions.
A few hours ago, I got the idea to have a magnitude multiplier that would scale back these larger values, and it didn't take long to find (via image search) a polar equation that did what I wanted to do (with a few tweaks):
I went into desmos to experiment. I plugged in real values so that I could work to a more general calculation.
I was able to discover a general equation to make sure that the function was less than or equal to 1, and then I rearanged the inner circle equation to make the minimum value of the function the subject.
I feel like the implementation is a bit crude since I have to remember to multiply currentMagnitude, prevMagnitude and SpacePoint.ButtonEvent, but if I try and do this multiplier filtering on the input values as they come in, I belive SpacePoint.ButtonRing would decay to 0. Remember, 3DxPoint just gets handed a new axis value and, at that point in time, doesn't know what angle the spacemouse is at.
Anyway, after once again being thrown under the bus temporarily because C++ divided 2 ints and probably injected a 0 into my double variable (see below for correction), I got the fix to work.
I've only tried it for a couple minutes but it already feels like the ButtonRing is more true to my intent. I'm now also considering if I need to use this for cursor translation too.
-
[E1][A] 3DxPoint now on Github
11/10/2023 at 18:52 • 0 commentshttps://github.com/Glodigit/3DxPoint
Decided to just upload what I've got, since it's probably 80-85% the way there anyway. As the saying goes, 80% of the work is in that last 20%, and I'd rather not delay #Coaxial Hotend [gd0144] and #Tetrescent [gd0150] much longer.
As an ergonomic pointing device to lightly browse the web, it's an OK solution (mostly because scrolling is excellent), but as I don't have even optical-square levels of ability and the ButtonRing still isn't as reliable as I'd like:
The solution... fails.
[18 Nov]
The good news (or bad news, depending how you look at it) is that the SpaceExplorer feels more comfortable to me than my almost-4-year-old mouse, and when I went to use said mouse (to get more speed/accuracy data), it felt somewhat alien, as if I haven't touched a mouse in months or something. My first thought was "I tolerated this?" (namely things like how it's only designed for my right hand or the surface it moves on needs to be a certain way).
Thus, I'm considering if I should continue to work on 3DxPoint to increase speed and accuracy moving the cursor and more reliabilty with the ButtonRing, or just get a "Used, Like New" Logitech G300S mouse and move on.
-
[C] 3DxPoint: Absolute Movement Zone
11/10/2023 at 16:15 • 0 comments2 days ago, whilst thinking of possible ways to obtain better precision and accuracy, I got the idea to have a small part of the range used for "absolute movement". So, instead of a trackpoint, it'll act more like an optical sensor seen on small netbooks like the OneGX1.
As I expected, I wasn't using anywhere near the full range of motion for moving the cursor. The first thing to try was to just send the 1 : 1 position of the spacemouse to the cursor, which is just taking away the previous mouse position from the current one, thus only the difference is sent. This produces a cursor that looks like it's trapped in a gravity well, and is rather jittery:
To turn this into something useful, I don't send the moments when the spacemouse moves closer to the center. Additionally, I send the usual movements when outside the "absolute zone". It looks like the mouse is running at stop-motion speeds, but it does work to increase accuracy and precison when the cursor is near a target. This was one of the major issues with the traditional method.
Unfortunately, things weren't as glamarous when I tested it out.
For starters, my best speed for White TIle, Don't Touch It was 50.499 seconds (my best with the traditional movement was 45.07). I can certainly feel that getting the cursor from place to place is slower than before.
My accuracy and precision have certainly improved, looking at these results:
However, I decided to also compare with the small optical sensor that's on Q3ti, my OEM 8" N100 Laptop from AliExpress. I believe it's the same thing as the one on the OneGX1. My results show that I'm still a long way off from a mouse replacement, though it also gave me the impression that I'm better on this claimed "7.2 * 7.2mm square" than on a trackpad.
Right now, I'm wondering if I should implement a look-ahead buffer and positional averaging to make the cursor appear smoother and reduce the chance of overshoot, or to just cut my losses, upload what I've already got and then buy a traditional mouse. I have just recently split the monolithic .cpp up a bit, so it may be a good time to publish:
Right now, 3DxPoint would be around about the "media center control" level of usability.
-
[C] 3DxPoint: ButtonRing improvements and BounceBack fail
11/07/2023 at 23:53 • 0 commentsSomething that I noticed was that I was overshooting or undershooting almost all the time. Thus, I got some quantatative measurements:
I found the game White Tile, Don't Tap It and it was a more forgiving way to test things out. The top 3 results were from touch, the next 3 were from my half-a-heart-durability mouse and the bottom two were from my SpaceExplorer. The "score" is actually the time, in seconds, it took to clear all the black tiles. Lower is better.
I quickly wrote some code to implement a "bounce back" feature, where if it was detected that I was slowing down, it'll invert the values. While it did do what I said it should do, it was like a mime hitting an invisible wall; cool to see, but I couldn't get anywhere. I found out that trackpoints have a feature called "negative inertia" that I'll have to look into.
I was also getting a few missclicks, and I suspected it had something to do with the of-chance the SpaceExplorer sends values like 90 -> 100 -> 96 -> 110 -> 115..., meaning that it triggered earlier than it should. The solution was to take the max from the previous 2 values, and this is one of the results:
I also took this time to fine-tweak the thresholds. The SpaceExplorer is somewhat non-ideal, since it's not stiff enough to make the force->value a linear thing. It's displacement->value, which sometimes means that the force reqired to displace the spacemouse is higher or lower (depending on things like grip, angle of the SpaceExplorer, etc).
I also need to add some kind of legacy scroll mode, as there are a small handful of applications that don't behave well with ultra-precision scroll.
-
[C] 3DxPoint: Sounds and Shortcuts
11/07/2023 at 23:31 • 0 comments[C] - Coding
I mainly worked on improving the ButtonRing and getting it to do things outside just mouse click events.
Sounds for click events
I was hoping that I could just piggy-back off a Windows sound, but I couldn't find anything suitable in windows/media/. Thus, I looked to see if there was anything that could be generated, and there's a function called Beep().
So I found this tone generator and started trying out some notes, and decided to go with
- C4 = Button Up
- D4 = Button Down
- E4 = Outer Button Down
- F4 = Button Edge Down
Yes. I had added a 3rd ring of buttons, which I'm calling the ButtonRing edge.
At first, I implemented the 100ms beeps to play on the onEntry event, but I wondered if it'll be better to get more of a live feedback and instead play the note when a threshold has been passed:
I also found a convenient place that doesn't require elevated access to use:
I've moved the log.txt to this location. This is also where I'd store the audio files.
Audio files?
Well, unfortunately, Beep() will freeze the mouse until it's made it's note. I tried a few async methods I found between BingChat and StackOverflow, but it didn't seem like the beep was being executed from a new thread. Additionally, my speakers made some kind of pop sound after Beep().
The easiest and simplest way I knew was to just go into AIR Ignite 1.3.1, pick a good (and somewhat luxurious) instrument (to complement the SpaceExplorer), and these were the 2 that I initially chose:
Spiccato sounds quite grand and posh, wheras Pizzicato sounds sharp-starting (which is the kind of sound I had in my mind for something that's supposed to represent a click event). I then made some test runs so that I could hear how it would ideally be like in practice:
Welllllll unfortunately, the PlaySound() command I used, while is asynchronous and doesn't freeze the cursor, cannot play more than one sound at a time. Research suggests I'd apparently need to be doing some complex stuff for that. Thus, Pizzicato sounded much less annoying, as it didn't sound like it was being cut off.
Along with that, I reduced the volume of the output notes so that they were less distracting / drone-sounding, as well as turning the "brightness" of the instrument down to 0 for the C3 note (as for some reason, it's C/D/E/G3 in Ignite, not C/D/E/G4) which removes that sharp start to the note. I think it makes sense since it represents a return to 0, not a click event. G is louder than the other ones as I thought it should sound like more power went into the click.
I've set up PlaySound() so that it doesn't play anything if the file can't be found, so a user could only use D/E/G and not put C into the folder (as, without headphones, it does sound like those notes just cut off midway). Later on, I also added a boolean so that the "play note on trigger" functionality can be selected (which is what I'm using now, again due to the PlaySound() limitation).
I've been using it for a few days, and the sound effects remind me of some kind of media-player interface, like Windows Media Center or the Xbox 360. Considering I've got as much control as an airmouse, it sounds accurate, at least.
Shortcuts
So I looked at the documentation for INPUT_KEYBOARD from Microsoft, and they actually had a sample that implements a keyboard shortcut:
It took less than 50 seconds to decide that there was too much boilerplate present, and I elegantly put everything into macros:
I'd then find out a few things. Firstly, the [ ` ~ ] key on US keyboards is the [ ` ¬ ] key on UK keyboards. Even though the [ ` ] is the same on both, Windows treats them differently, so they've got to be different virtual keys. Secondly, only the ASCII alphanumerics map directly to their virtual key code counterparts.
Thirdly, that for-each loop strat I tried doesn't work. I have to do the old fashoned
for (int i = 0; i < ARRAYSIZE(k); i++) {}
for the INPUT types to all be set correctly.
Fourthly, I can't use a case statement for my PC-to-compile-for selector, but an if / else implementation is fine.
I did decide to make the names more generic though:
To try and find the keycode I was looking for, I turned to the Microsoft docs again, but the sample code just didn't work:
The good news is Microsoft totally already foresaw this specific predicament and has gone out of their way to usher in the Advent of A.I., allowing me to literally ask Bing:
I created a new C++ Console App and ran it, then pressed the key in question and got this:
It technically works, but I wanted to ask Bing if a tweak could be made. It actually delivered:
The virtual key code for Escape is 27. To actually exit the program, the Escape key needs to be held down. Anyway, converting 223 into hexadecimal and then consulting the docs, I found this (but I'm 99% confident I could've just used 223):
I started making some more, but it only took me 2 of these to decide to create a new (and later shortened to) TapKey() function:
Thus, I think the final keyboard shortcut making experience looks rather nice:
I later want to implement some way of querying the .exe that the user has focused so that, like 3DxWare, 3DxPoint changes these shortcuts depending on context.
-
[A] Introducing 3DxPoint: The 3D Trackpoint
11/03/2023 at 23:58 • 2 commentsI'll be honest. I knew this was going to take a while to do, and so I avoided doing it until my £16 mouse finally actually stopped working. Like, it technically works, but the cable had to be within a specific angle or else it'll disconnect. Well that angle has been getting smaller and smaller over the passing months and, a week ago, this angle was too small to do anything meaningful. I can't model #Coaxial Hotend [gd0144] with the Windows 10 touchscreen trackpad, so I really had to do something and do it now.
Since then, I've spent about 36 combined hours to develop the 3DxPoint.dll that implements all the features I mentioned in the previous log, and other than some refinements that I'll mention at the end, I've got a working minimum viable product.
Getting a new Visual Studio project set up
All the way back in April, i got an email from jwick (mod on the 3Dconnexion fourms) which included the source code for a modified 3DxSample.dll that was mainly to get mouse button presses on an Axis instead of a Button. He mentioned that useful information about the true capabilities of the 3DxWare driver is in a beta forum, but it seems pedestrian users like myself don't have access to that.
So, the first order of business was to rename the project to a more fitting name, and I thought of 3DxPoint, short for "3DxWare X Trackpoint", since the control should be very similar to a massively enlarged trackpoint.
Now, it seems that just renaming a few things in Visual Studio to "3DxPoint" wasn't going to work, so I created a brand new DLL project and deleted the automatically created files to bring in the new ones. And then I got this complaint:
Well, as I soon found out, those files I deleted were more or less the same thing as the 3DxSample files but with a new name (I guess thing's have changed since 2015, which was the datestamp of those files), so I backtracked.
Obviously, stuff was still broken, mainly to do with pch.cpp. This answer solved it:
I got things to compile, but I had warnings:
I was looking at the code and it didn't look like that was possible for fp == 0, but I didn't want to assume things that could be the cause of bugs. Well then I found this, showing that it is indeed possible:
I just tacked "&& fp != NULL" inside all the if statements.
Getting 3DxWare 10.6.4 to run a DLL
A hurdle I hit very quickly was that, like 3DxSample.dll, 3DxPoint.dll didn't seem to be doing anything. There's an init function that writes to a fill every time it's called, and nothing was being written.
After doing some trial and error, I decided to reread the instructions slowly and carefully:
1) Save it into %ProgramFiles%/3Dconnexion/3DxWare/3DxWinCore/Win64/DLLs/.
I kind-of just assumed that the DLL went in the same directory as the XML that used it. I only have a "3DxWinCore64" folder, so I used that instead.
2) Add these AxisActions to an app-specific cfg, or Global.xml
Now, I thought that Desktop.xml counted, but it actually doesn't. This is what happened.
I added a ButtonAction in Global.xml.
I restarted the driver and looked at 3DxPoint.txt:
I audiably ghasped:
The AxisAction that I defined in Desktop.xml but not Global.xml magically started working:
Initial testing and understanding
One of the frist things I found out was how the deadband affected the readings. This is a deadband of 40 compared to a deadband of 0:
This also tells me that the absolute max value produced is most likely 350.
I also found out that the ButtonAction set in Global.xml doesn't actually need to be used for anything in the same xml for the 3DxPoint.dll to still work for Desktop.xml.
Code cleanup and consolidation
All these block-if's to deal with logging were making things a bit cluttered and it was all boilerplate anyway, so I turned some parts into macros:
I did some research and changed the first if to a block if (see below), though I feel like the above solution was more elegant now that I'm looking back on things.
Then I found out this nice way to do enums, which I used in the goal to consolidate functions for left/middle/right button presses (from 3DxSample) into a single, unified function:
I also found out about the "#if 0" statement to quicly "comment out" parts of code. I could also use "#if 1" to be able to minimise entire sections of code.
This SendMouseButton eventually grew to include more or less everything done by a typical mouse, as seen by the MouseEvent enum.
I had also read the docs in more detail, and it turns out jwick had already implemented the smooth scroll feature in the original 3DxSample.cpp. Ultra-smooth scroll looks and feels so much better, and it even works in Fusion 360!
Getting the ButtonRing magnitude and angle
The ButtonRing is what I'm calling the virtual ring of buttons activated by tilting the spacemouse in that direction. I also understand that, from looking in 3Dconnexion forums about using the spacemouse as a 2D mouse, some prefer to tilt the spacemouse to move the cursor, thus the ButtonRing would be activated by translations instead of tilting.
What I started off with was a struct that had all the stuff I'd think I'd need (for 3DxPoint in general) and then some logging:
It feels great to finally use something I learned in maths class (well, "Further Maths") in the real world. Complex numbers allow for an easy avenue to convert an X and Y value into a magnitude and direction.
As you may also see, I have "bool Button[8][2]" instead of "Button[8]". As I'm working on a force-sensitive project myself that has its roots in double-actuation switches (see #Tetrinsic [gd0041]) I wanted to try to get dual actuation virtual buttons on the ButtonRing.
Everything seemed to work ok, but I wanted a nicer looking log message that actually put the magnitude / angle under the spotlight. I had to find out how to save unicode characters to a file, but I got this solution:
Licensing
So now I had spent a couple days on this and the percentage of 3DxSample / jwick code I was using had become quite low, so I finally decided to look into the wide world of open source licensing.
I first found out that this is the header, which is a format I've seen from the QMK Taipo implementation:
Then the differences between 2-clause BSD (and how it's very similar to MIT) and 3-clause BSD.
And then I found this reddit comment:
Since I played Burnout 3 when I was a kid, "Shake That Bush Again" (see video below) was already playing in my mind upon reading "boost", since that's one of the main elements of the game. It was all too easy to believe that they were singing "Shake That Boost Again", and I'd be tapping the boost button in time for the beat when it played.
There's actually a website page for it, and it mentions a nice bit of history and even a convenient FAQ section.
So yeah, it's MIT compatible and I like the name of it so I went with it.
Speed Multiplier
The next thing to work on was being able to lift and lower the spacemouse to speed or slow down the rate of the cursor and scrollwheel. Thus I started plotting graphs on Desmos / Excel to see what would give me the feeling I desired in the range 0 - 2 (of which, -350 to 350 was mapped to)
I tried the above one and it didn't feel that fast when lifting the mouse, and this is probably why:
I just used a classic exponent, since being able to slow down for more precision is more important than speeding up to quickly jump from one side of the screen to the other.
I also noticed that the SpaceExplorer liked to lock towards cardinal directions:
I'm not actually sure I can see this as a bug or a feature. There's many times when I am just trying to move the cursor up/down/left/right and other pointing devices make such a task very hard. Unfortunately, this extends into the 3rd dimension, making the speed multiplier axis less responsive than I'd like at times.
I also found out this nice shortcut when doing all these tweaks and changes:
I also implemented a mirroring feature so that a button could be pressed to swap from right to left handed use.
Selecting a button from the ButtonRing
Now, I don't fully understand the code because Me In The Zone wrote it, and trying to juggle what was happening where was a strenuous mental exercise. If I could code closer to thinking speed (cough #Tetent [gd0090] cough) then it wouldn't be so bad; instead I have to put some considerable energy trying to keep implementation ideas in my short term memory long enough to either implement it in the code, or write it somewhere. For example, here's my coding equivalent to "I sketched this idea in Paint3D":
I've read online that there are coders, programmers and software developers that claim that their typing speed is never their bottleneck, but their thinking speed. I'm not sure if it's a benefit or a drawback, but I'm 100% on the other side of the coin. Perhaps I'm just a "Documentation Driven Development" kind of guy; I think "How would I explain the implementation of this feature on Hackaday" instead of "How would I write a test for this feature" (Test Driven Development) or "How would I implement this feature". Maybe I should look into Behavour Driven Development?
Returnint to topic. All I want to mention is that, even though there's like 4 nested if statements, actually adding button commands has been made straightforward by reading the LogMessage commands:
I feel like it's spaghetti code because there's all sorts of booleans doing things around the function. It makes sense, but I do wonder if there's a more elegant way.
Anyway, I think it'll be much better to explain the behaviour.
The first thing to know is that, for a physical button, the minimum force to press the button from up --> down is higher than from down --> up. I've implemented this like a Schmitt Trigger:
Next, there's both an inner and outer button, so it's not like I can just turn on a button the moment I pass the threshold. When I start to tilt the spacemouse on the SpaceExplorer, all the values are consistently larger than the previous one up until the point where I actually want to stop tilting. Observe the following diagram I made in Paint3D, where the X axis is time and the Y axis is the magnitude of tilt:
The dark red line is one such tilt movement and first stops increasing above the outer threshold, so the outer virtual button should be activated. So that users don't have to strain their hands, they can now reduce the amount of force needed to keep it enabled. It only turns off when the magnitude falls below the exit threshold.
The orange line stopped increasing above the inner threshold, so the inner virtual button should be activated.
Now lets say a 3rd movement comes along, shown in bright red:
As you can see, even though it starts off noisy, all the noise is under the inner threshold so it doesn't count to anything. This could also be from a previous movement, where the user never fully stopped tilting the spacemouse (say, for a double click) . Since the first time the bright red line stopped increasing was in the inner threshold, the inner button will be enabled until it falls under the exit threshold. It won't spontaneously decide to select the outer button just because the user happened to cross the outer threshold.
You should also remember that I don't get a continuous curve, but a list of values:
I've set it so that the virtual button isn't pressed down when the very next value completely skips over both thresholds, as the alternative would be a very quick click.
That was a 1D representation. To make it work in 2D (so accidentally going into a different octant didn't do anything), the complex number is saved. I called it triggerEvent, which is "static", meaning that it is saved between function calls:
The reason onExit exists is because I need to be able to execute a virtual button_up event.
I was considering coding up some way to have an easily adjustable way to have an arbritrary amount of virtual buttons, but I decided that such a feature was just feature-creep and stuck with hard coding 8 x 2 buttons.
One of the things I needed to do was check if an angle was inbetween 2 other angles, so that the octant could be determined. I searched it up, expecting there to actually be a standard function for this in C++, but it turns out that doesn't exist and Bing stepped up to generate something:
So I pasted that character soup in the codebase and, since I'd been coding straight for hours, I decided to take a break (reading about open source community's general funding issue) for like 10 minutes, and I came back with the idea that there was a more readable way to write this function:
I guess, if I squint now, I can understand that it doesn't discriminate between minimum and maximum values
Trying things out
My idea, with 4 of these 16 virtual buttons at my disposal, was to do the following:
- West Inner: Left Click
- West Outer: Right Click
- East Inner: Middle Click
- East Outer: Mirror
This is for my right hand, which I usually use with a mouse. The first time I actually set it up and tried it put a massive smile on my face because it actually worked. The analogy I thought of was "3D Touch" from Apple:
😂I like how the woman in the video is says "Think of it like right clicking a mouse..." about 3D Touch and now I'm saying, 8 years later, "Think of it like using 3D Touch on an iPhone..." about right clicking.
I was thinking that I'd have to do some kind of nifty timer based logic or something, but just waiting for the moment when I stop increasing force is quite reliable. What isn't reliable is knowing when I've actually crossed a threshold, and it validates my reasoning behind haptic events for #Tetrinsic [gd0041].
Limitations and future improvements
The first minor limitation is that 3DxWare needs to be running as Admin, or else 3DxPoint isn't going to work if you open up admin-level programs like Task Manager. The next one is that moving the spacemouse doesn't remove the screensaver. Last limitation that I've found so far is that 3DxPoint wont work if the program in focus is not responding.
The immediate future improvement I want to look into is perhaps having a dynamic threshold based on how far down the spacemouse is pushed. It seems that I get quite a few accidental button presses when I'm also trying to move my cursor with the speed multiplier not equal to 1 (a.k.a I've lifted or lowered the spacemouse). Perhaps this is just a skill issue, and will help me have better control when using Fusion 360 in the traditional 6 axis mode.
(Tip for Fusion360.xml - change ResponseCurve to 1.0. Now the SpaceExplorer feels a lot more connected to the movements I want to perform.)
Another improvement is to add an enum for the PC I want to compile 3DxPoint.dll for, as the keyboard shortcuts I need vary between #Teti [gd0022] and Q3ti (my 8", Intel N100 laptop). This is also to allow me to quickly put out a general-purpose 3DxPoint.dll that only has the mouse-related virtual buttons I mentioned earlier.
Obviously, changing my sync client from OneDrive to a Github repo is also on the list. It was just that I didn't want to have yet another thing to keep track of, compared to OneDrive where I could save 3DxPoint.cpp on Teti and pick it up again on Q3ti without having to remember to commit and sync. I also need to clean up code I thought I was going to need (like the Octant enum) but didn't.
Looking at the logs, I don't usually go above 180 when activating the outer button, so it might even be possible to have three sets of button rings. Who would even need a SpaceMouse Pro when you've got that many commands at most a "3DxPoint Toggle Button -> Tilt -> 3DxPoint Toggle Button" away?
I might also want to consider removing buttonAlreadyPressed and instead implement an onEntry boolean instead. It might fix this rare but known bug that I don't get a down event (for example, after line 10134):
Implementing onEntry
This code above has already become more understandable to read.And it still seems to totally works!
Conclusions
I've been testing out the SpaceExplorer for most of today, and even though my precision with it isn't quite where I'd like, I feel like an actual professional when using it; well, like a person in stock-footage acting like a professional:
It might be because the cursor moves smoothly, like in motion graphics / infomercials.
Honestly, considering 3Dconnexion and everyone has been calling this line of devices "SpaceMice" for over 10 years, I'm suprised this functionality isn't baked into the driver itself. Reason 1 out of 2 why I never got much use out of my SpaceExplorer was because I'd have to be hotswapping a hand from the keyboard/mouse to it, and 2 of 2 was that I didn't get much experience using the device outside of Fusion360.
A SpaceMouse Wireless + a vibration motor + driver support (+ round display) would make for an outstanding professional input device if 24 virtual buttons are reliably usasble. Perhaps #OS3M Mouse could take it all the way one day.
-
[T] 2D Spacemouse strategy
10/27/2023 at 00:38 • 1 commentWhat I'm going to try to implement is as follows:
- Left / right / forward / backwards translations controls the cursor position.
- Height controls a cursor speed multiplier.
- When translated, the cursor moves faster or slower dependent on how much the cylinder is lifted / lowered respectively.
- Rotate (like a dial) to scroll. Specifically, "ultra-high precision scroll" such as the scrolling from a Windows precision touchpad, not the dedent-like default scroll.
- Looking at the Windows documentation, I believe RAWMOUSE would achieve this.
- Tilt backwards = left click and tilt forward = right click.
- Ideally, this would be implemented as an angle and magnitude so that more mouse/keyboard events can be added in the future. For example:
- Right-button-down event when -20 < Tilt_Angle <= 20 AND Tilt_Magnitude > 200 AND another virtual tilt button isn’t already active
- Right-button-up event when Tilt_Magnitude <= 200
- Ideally, this would be implemented as an angle and magnitude so that more mouse/keyboard events can be added in the future. For example:
-
[X] Set-up success! Starting to learn Taipo.
10/20/2023 at 10:24 • 1 commentI wanted to copy-paste all of dilp's work, since it seems that he's stopped making commits specifically for Taipo. After looking around to see if I could just download a single folder in a repo, I somehow found my way into opening a PR for my own repo:
Unfortunately, RGBLIGHT_ENABLE = yes still doesn't work, but I found out that reducing Taipo_tap_timeout from the default 150 to 50 made things MUCH more responsive:
- TP_TLP's numerical keycode is the smallest numerical keycode, so var key is a number between 0 and 19
- The state to work on is then determined, as key / 10 would truncate to int 0 if key is less than 10 and truncate to int 1 if over.
- In dilp's actual layouts, the only things on _TAIPO are TP_ keys and KC_NO, so line 1181 probably deals with that.
- Not sure exactly what the rest of the first function is doing
- the second function seems to check if both the state timer is non-0 and passed the time allocated...
and that's about the extent of my understanding. I'm sure the code is dealing with things like holding the ' y ' combo being able to result in "yyyyyyyyyyy" sent to the host. I'm just trying to understand what could be the issue with RGBs and if I could implement something like TAIPO_PREFER_LEFT and TAIPO_PREFER_RIGHT so that it's possible to choose between a Keyboard Cat--esque typing style and a stenography-esque style.
I also tried to add unicode characters to my layout, but I got unexpected behaviour:
Finally, I could now start practicing in Ngram Type:
I started trying to alternate all the time, but I found it was easier to understand the finger movements if I just did one round with only my left and one round with only my right hand. Then I wanted to look ahead and see if there'd be any issues with my current setup before I hardcoded my neural network into a corner.
-
[X] Setting up Taipo-enabled firmware
09/16/2023 at 14:25 • 0 comments[16 Sep]
I was thinking that I was going to set this up and then make a log about it, but it's taking a bit of time so I thought a live-running log format would be better.
So far, I've tried to implement Taipo.c from a QMK source instead of a QMK->Vial fork and made everything barebones and turn things on, one step at a time.
It seems that Taipo and my keyboard works when RGBLIGHT_ENABLE = no in my rules.mk, and fails when set to yes, even without anything RGB related in the keymap.c. Unfortunately, turning rgblight off in my vial config doesn't fix the unresponsiveness issue.