-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Output from string/Unicode helpers broken when CapsLock is ON #128
Comments
Context is only passed to keymap/modmap conditionals...
You can look at where commands are called: https://github.com/joshgoebel/keyszer/blob/main/src/keyszer/transform.py#L551 Commands simply do not have access to this information. Context isn't currently even available that deep into the transform... |
Oof. Without that information I don't see how we can get those functions to adapt to the state of the CapsLock LED. I gather this doesn't affect keyboard shortcut combos because the system ignores the CapsLock state in those cases, but when we're "typing" characters to output it really messes with things. Disables the Shift-Ctrl-u shortcut to initiate Unicode entry, and so on. I will look at those locations, but do you have any other idea how this could be fixed? Or do I just need to look at passing context all the way through transform so that it's available to these functions when they get called? Wait, maybe I can just use a wrapper from within config, and pass the context in that way? No, if it's only passed into the "when" part, does that mean it's also not available in "mappings"... Hmm... 🤔 |
Do you think it's possible to do a real-time test within the processor function where I "assert" some normal letter keystroke and check whether it came out as lowercase or uppercase? |
What would you do if you had access to caps lock state? Output the opposite of what key was pressed (lower vs upper) to get around caps lock? |
For the Unicode function, I think the only thing that needs to be done during the creation of the list is to prepend and append a CapsLock keystroke, to reverse the state and allow the Shift+Ctrl+u shortcut to invoke the Unicode entry method. I don't think the method particularly cares whether the hex letters are upper or lower. For the string processor, I'm not exactly sure what needs to be done yet. But most likely just something similar, adding a CapsLock keystroke at the beginning and end of the combo_list, to reverse the state during the output of the string. I always use the Unicode function directly, but there is this inside the string processor:
So it may actually be a little more complicated in the case where they interact. Have to make sure there won't be duplicate reversals of the CapsLock state. I'm sure I can figure it all out, I just need to somehow get access to that dang CapsLock state. |
Oh, I think I kind of broke that part of the string processor, since both of the processor functions now return functions. 😛 I'll need to find some way around that. Global var, maybe?
|
Phew. 😓 Managed to fix it with a global variable that gets set inside
Anyway, as far as I can tell everything is working again. Embedded Unicode characters, extended ASCII, or either of the Unicode Python notations in a string are all coming out like they should.
Now I just need some kind of method for checking the CapsLock state, and it shouldn't take long to wrap up the fix. Maybe I can just do some sort of tripwire keymap like the one in the Option-key special character setup, that's constantly calling a function that's checking the state and setting a global variable. |
Well, I'll have to come back to this and make sure everything is really nailed down, but it works. It's still a bit of a hack because it requires a "tripwire" keymap to send the context object into a new function in At first I tried to just put the function in my config file, but that didn't work to update the variable in a way that the processor functions would have access to the state of the variable. Apparently you can do this between modules, but I couldn't make it work that way. Results are looking good:
I did decide to just go with reversing the use of "Shift" for the letters in strings, while the Unicode processor disables CapsLock and then re-enables. This way there is really no conflict between the two functions, whether you use the Unicode processor directly or access it by proxy through the string processor. Works either way. Also had to split up the The tripwire
And the function inside
|
OK, even though at the moment this requires the tripwire keymap "hack" in the user's config file to actually do anything meaningful, I'm going to clean up the code changes to It's not harmful if nothing is updating the variableThe changes, if there is no tripwire keymap (or other method) sending the context into the global variable in
The variable is just initiated as It makes changes that are necessary to fix the issueThe main thing is that the code changes convert the existing simple functions that were just returning keystroke lists, into compound functions that return active inner functions that will stay in memory, and can now adapt to the state of the global variable that will mirror the CapsLock state. It will work no matter what kind of method is developed in the future to update that variable, with or without the use of the tripwire keymap. Also it implements the logic changes so that the "shift reversal" only applies to alphabetical keys that need it, and doesn't touch the numeric/digit characters. There is no conflict with the operation of the Unicode function and its need to disable the CapsLock ON state before issuing the Shift+Ctrl+u shortcut. Doesn't harm troubleshooting too muchAll the keystrokes that are created by the processing functions will still show as debugging output keystrokes n the log, so there really isn't much of an issue created by returning "opaque" function objects rather than lists. There wasn't really any logging going on with the existing simple functions anyway. Debugging output can always be added back into the inner processing functions if a problem crops up. Future enhancementI'm envisioning some part of the code, where the context is already available, calling on the My Option-key special characters now come out the same with CapsLock on or off. With the current code you'd just see the raw Unicode address for each character on a new line when CapsLock was on.
|
Oh ,it's only key context, not state - it doesn't include WHICH key is pressed... I'm ok with that falling thru to the commands... so you'd really only need something like this I think...
So every command function gets the state passed to it - just like conditionals. |
I figured something relatively simple like this would allow it to work. I was about to start trying something similar, but this is extremely helpful.
Just guessing at the moment, but that means this should allow the context to be accessed in the processor functions without needing the new CapsLock LED status function and the global variable, correct? (In other words, I shouldn't need the tripwire keymap anymore?) I'll have to try it to be sure I actually understand what's happening here. But it looks very promising. |
Right, the internal state is just passed directly to commands - the state is maintained in the engine, not a global. |
VSCode is showing an error here, "Non-default argument follows default argument" from Pylance. Not sure if that actually has any real consequences, but the linting definitely doesn't like it.
Should be fine to move the default argument to the end, right?
Thought so. Sounds good. There's definitely no need to know what key is being pressed. Just whether CapsLock is ON or OFF. |
Yeah, need to change the order. |
No problem. But there is an exception when I try to run this.
|
You've got the param order wrong likely... |
I think this helped, but now I get other errors, including an error with my custom
I'll have to update the processor functions to accept the "ctx" and see what happens. |
OK, that was a little bit complicated, but everything seems to be working, at least not having errors. Still need to actually use the "ctx" properly and see if that works. A possible complication is that I had to add a "ctx" parameter to the inner function of my Pretty sure this means that any custom function the user makes will now have to accept the "ctx" being passed to it, and the user will have to understand that from this relatively generic error message (and follow the traceback info):
There is the traceback but a lot of users will find it difficult to actually understand how to fix the error. Just trying to think if there is a way to make the usage of "ctx" in custom functions optional, or if this is the price that must be paid... |
Oh I wonder if that makes the commands REQUIRE an argument? If so that's annoying and we'd need to analyze them first to find out if they want an arg or not. |
Yeah, I think the It's kind of fascinating that my whole config file didn't immediately blow up because the Anyway, looks like we have to dig into using something like |
I’m kind of taking a break but started wondering if this could actually be as simple as just doing a try/except fork to catch the positional argument error and send the contextless version when there is an error. Edit: Seems to work OK. Still getting context inside of the processing functions, but was able to remove the parameter from
🤞🏽 Fingers crossed that this is actually a good solution and all that needs to be done. Oops, gotta remember to except only the specific error and not leave a generic Still seems to work OK.
|
I think it's just an if/else around something like |
Is there an advantage to that over the try/except block? More reliable for this specific issue? That just shows the length (count) of the parameters, which is fine if it's zero. But if it's one or more I'll need to do a check for "ctx" being in the parameter list that comes out:
I'll have to play around with this a bit. |
What would the purpose of any other arguments be? You can use closures to pass any values from an outer wrapper... so a command fn would either only take 0 params, or 1 context param, nothing else. No? |
Mmm... By "command fn" do you mean the inner functions? I haven't really grasped yet why the inner functions are the only ones that receive the "ctx" parameter. I did notice in the past that it couldn't be passed in via the outer function. My
I thought maybe someone at some point would have some sort of reason to have more than one parameter in an inner function, but if that's never going to be the case I can pare this down to just the |
Alright, if you think this will be good enough, I'll finish modifying the processor functions to work with
|
Submitted PR #129. Let me know if you see some sort of problem with it, or want something changed. Oh, and thanks for the help and suggestions. Really made this a lot easier. |
unicode_keystrokes
?
Bumping this. As far as I know, the fix is complete and working perfectly. See something that should be done differently? |
This should be resolved with the merge of PR #129. Closing. 🎉 🎉 🎉 🎉 🎉 🎉 🎉 🎉 👏🏽 |
I'm trying to fix the bug that breaks the string and Unicode processor functions when CapsLock is "ON". First step was to make them into inner functions so they might be able to respond in real-time in different ways depending on the state of the CapsLock LED. That works fine. Now they no longer just create a static list once on startup. But, I'm failing to understand how to get access to the key context object (and thus the "capslock_on" property) inside either processor function. Or really anywhere in
config_api.py
.There's something really fundamental about how the context object works (i.e., where it "comes from" and how it becomes accessible) that I've obviously never understood completely. The config file doesn't directly import the
KeyContext
class fromkey_context.py
or do a "KeyContext(device)" anywhere, or define "ctx = whatever" anywhere, yet whenever you do a "lambda ctx" you can suddenly access all the different properties with things like "ctx.capslock_on".I was able to use the "ctx" object in my
matchProps()
function with no difficulty, by passing it in as a parameter in the inner function. But when I try the same trick with the_unicode_keystrokes
inner function inconfig_api.py
, it acts like it has no idea what that parameter is.So I'm kind of stuck until I can understand how to access the "capslock_on" property from within these inner functions, at the moment the Unicode or string processing function is "fired" by an input combo.
Been struggling with this for a while. Any kind of clue would be helpful.
The text was updated successfully, but these errors were encountered: