yqrashawn / GokuRakuJoudo

config karabiner with ease
GNU General Public License v3.0
1.16k stars 121 forks source link

Fast inputs cause overflow #137

Closed uwuthless closed 2 years ago

uwuthless commented 3 years ago

Hi. Have been struggling with this through weekends. My goal - if caps_lock is on (not continuously pressed) - have button "i" send up_arrow if caps_lock is on AND spacebar is pressed - have "i" send page_up if neither - "i" should have normal behaviour, print "i"

(i am trying to setup navigation with "ijkl", when caps_lock is pressed, i == up, j == option+left, k == down, l == option+right, when spacebar is pressed, i want the buttons to have different behavior, i == page_up, k == page_down, j == left, l == right)

I have tried using layers for this, specifically - :space-layer {:key :spacebar } - does not work (in my findings - because pressing spacebar with caps_lock off sends a different signal from pressing spacebar with caps_lock on), and I did not find any example of how to make it so :!Pspacebar would also trigger this layer

I have tried using 'simultaneous press rule' for spacebar + i , namely in a line like [:!P#Sj :left_arrow] [[:!P#Sj :spacebar] :!Oleft_arrow] which, when calling 'goku', prints ERROR: invalid <from> in main section's move with ijkl Caps Space Failed!

The variation [[:j :spacebar] :!Oleft_arrow] compiles, but I would like to be able to hold space to traverse the text, not be forced into pressing it every time

I have come up with the following code -

{       
                      :main [{:des "move with ijkl Caps Space"
                           :rules [

                     [:!P#Sspacebar ["space-mode" 1] nil {:afterup ["space-mode" 0]
                                           :alone :escape}]
                     [:!P#Sk :page_down :space-mode] 
                     [:!P#Si :page_up :space-mode ]
                     [:!P#Sj :!Oleft_arrow :space-mode ] 
                     [:!P#Sl :!Oright_arrow :space-mode]

                     [:!P#Sk :down_arrow :!space-mode] 
                     [:!P#Si :up_arrow  :!space-mode]
                     [:!P#Sj :left_arrow  :!space-mode] 
                     [:!P#Sl :right_arrow :!space-mode]

                     ]
                     }
                     ]}

But it has a huge problem - if the keys are pressed long enough + fast enough (5 cps for 30 sec), the Karabiner goes crazy, the entire keyboard stops responding, the following inputs get buffered, and then the buffered inputs start randomly spatting into the input stream, which lasts for about 5 minutes ruining the workflow.

What I have found is when there is no variable in the script, it seems to handle the load better, when I am removing the line [:!P#Sspacebar ["space-mode" 1] nil {:afterup ["space-mode" 0] :alone :escape}] this seems to stop the overflow on high load.

Could you please suggest a solution for my use case, either without the usage of variables, or so it doesn't do the overflow. I might be doing something wrong, what do you think?

yqrashawn commented 3 years ago

I think you need to define your own "caps_lock is on" layer. The !P means caps_lock is pressed instead of it's on.

uwuthless commented 3 years ago

I think you need to define your own "caps_lock is on" layer. The !P means caps_lock is pressed instead of it's on.

could you please provide an example of that? I didn't find the clear example in the doc.

Also, how do i make complex boolean conditions (for checking whether 2 conditions are 1 (true) simultaneously)? In conditions, I can write [:space-mode :caps-mode] , but is it "AND" or "OR" ? What is the correct syntax to cause modification only when the composite boolean condition is true? Say, I want to do [:#Sk :down_arrow (IF (:space-pressed-down-mode AND :caps-on-mode) OR :caps-pressed-down-mode)]

what is the syntax or a workaround (maybe, through multiple layers) to achieve that ? Could you please provide an example, I've honestly tried finding examples and solutions and found none, this is why I wrote the post. Thank you for your time.

uwuthless commented 3 years ago

upping the thread, please provide an example of creating the layer of "button is pressed down", and how to create complex boolean conditions, because currently my config looks like this


        :profiles
 {:uwuth {:default true
         :sim     10
         :delay   10
         :alone   40
         :held    30}}
        :main [{:des "move with ijkl Caps Space"
             :rules [

[:#Scaps_lock [ ["space-mode" 1] ["both-mode" 0] ["s-mode" 0] ["f-mode" 0] ] nil {:afterup [["space-mode" 0] ["both-mode" 0] ["s-mode" 0] ["f-mode" 0] ]:alone :spacebar}]

[:#Ss [["both-mode" 1] ["s-mode" 1]] :f-mode {:afterup [["s-mode" 0] ["both-mode" 0]] :alone {:key :escape}}]
[:#Ss ["s-mode" 1] :space-mode {:afterup [["s-mode" 0] ["both-mode" 0]] :alone {:key :escape}}]
[:#Sf [["both-mode" 1] ["f-mode" 1] ] :s-mode {:afterup [["f-mode" 0] ["both-mode" 0]] :alone {:key :escape}}]
[:#Sf ["f-mode" 1] :space-mode {:afterup [["f-mode" 0] ["both-mode" 0]] :alone {:key :escape}}]

[:i :!Spage_up :both-mode ]
[:i :page_up :f-mode ]
[:i :!Sup_arrow :s-mode ]
[:i :up_arrow :space-mode ]

[:k :!Spage_down :both-mode ]
[:k :page_down :f-mode ]
[:k :!Sdown_arrow :s-mode ]
[:k :down_arrow :space-mode ]

[:j :!Sleft_arrow :both-mode ]
[:j :left_arrow :f-mode ]
[:j :!SOleft_arrow :s-mode ]
[:j :!Oleft_arrow :space-mode ]

[:l :!Sright_arrow :both-mode ]
[:l :right_arrow :f-mode ]
[:l :!SOright_arrow :s-mode ]
[:l :!Oright_arrow :space-mode ]

(I'm using "caps lock" as the "mode button", 'S' to select, 'F' to traverse documents with different scale) And I believe it can be drastically simplified with OR and AND boolean operators, and purged of ill performance with layers, could you please provide an example of that?

uwuthless commented 3 years ago

update: I have managed to remap caps -> ctrl, s -> left_shift, f -> right_control , and use the optional modifier #S for merging non-shift and shift versions of line into one, which made code twice as succinct, but the problem of overflow of pressed key memory buffer might still be a thing (though me testing it showed no signs of it), so I ask for the opinion on optimization of this config. Also I give consent on posting it (or its modified version) as an example of Goku (either in example dir, or in in-the-wild dir, or elsewhere, just note my username - uwuthless)

{       

 :profiles
 {:uwuth {:default true
         :sim     10
         :delay   10
         :alone   150
         :held    30}}
        :main [{:des "move with ijkl SF"
             :rules [
[:##caps_lock :left_control]
[:!Ts :!Tleft_shift nil {:alone :!Ts}]
[:!Tf :!Tright_control nil {:alone :!Tf}]
[:!TSf :!TSright_control nil {:alone :!TSf}]
[:!TWs :!TWleft_shift]

;movement
[:!T#Si :#Sup_arrow]
[:!TW#Si :#Spage_up]

[:!T#Sk :#Sdown_arrow]
[:!TW#Sk :#Spage_down]

[:!T#Sj :!O#Sleft_arrow]
[:!TW#Sj :#Sleft_arrow]

[:!T#Sl :!O#Sright_arrow]
[:!TW#Sl :#Sright_arrow]

;symbols remap
[:!T1 :!S1]
[:!T2 :!S2]
[:!T3 :!S3]
[:!T4 :!S4]
[:!T5 :!S5]
[:!T6 :!S6]
[:!T7 :!S7]
[:!T8 :!S8]
[:!T9 :!S9]
[:!T0 :!S0]
[:!Thyphen :!Shyphen]
[:!Tequal_sign :!Sequal_sign]
[:!Topen_bracket :!Sopen_bracket]
[:!Tclose_bracket :!Sclose_bracket]
[:!Tdelete_or_backspace :!Odelete_or_backspace]
[:!TWdelete_or_backspace :delete_forward]

;;todo caps remap for all except ijkl SF

                     ]
                     }
                     ]
}
yqrashawn commented 3 years ago

Hi, sorry for the late reply check this rule https://github.com/yqrashawn/yqdotfiles/blob/cdca2d64070234f98963d7b18a5e9aa54fc04ea2/.config/karabiner.edn#L63 remove the #_ prefix to enable it.

This maps caps lock to toggle cap layer between 0/1 in cap layer, ikjl to arrow keys, modifiers+ikjl to modifiers+arrow keys in cap layer, press and hold space space to set capspace to 1 when capspace is 1, ik to page up/down

yqrashawn commented 3 years ago

(for checking whether 2 conditions are 1 (true) simultaneously)

:cap
[:##i :up_arrow ["capspace" 0]]
[:##k :down_arrow ["capspace" 0]]

this combine the two conditions as cap is 1 AND capspace is 0

[:space-mode :caps-mode] , but is it "AND" or "OR" ?

this is AND OR should be implemented as multiple rules

(IF (:space-pressed-down-mode AND :caps-on-mode) OR :caps-pressed-down-mode)

assume we are mapping 1 to 2 with this condition, it should be something like

[:1 :2 [:space-down :caps-on]]
[:1 :2 [:caps-down :!space-down]]
[:1 :2 [:caps-down :!caps-on]]

an example of creating the layer of "button is pressed down"

https://github.com/yqrashawn/yqdotfiles/blob/61dae1e5363a37e01dfca779c64c99639a11b39f/.config/karabiner.edn#L72 this line means: when space is down, set capspace to 1, when space is up, set capspace to 0 and insert space when space pressed alone. It's under the :caps so this only works when caps is 1.

uwuthless commented 3 years ago

(for checking whether 2 conditions are 1 (true) simultaneously)

:cap
[:##i :up_arrow ["capspace" 0]]
[:##k :down_arrow ["capspace" 0]]

this combine the two conditions as cap is 1 AND capspace is 0

[:space-mode :caps-mode] , but is it "AND" or "OR" ?

this is AND OR should be implemented as multiple rules

(IF (:space-pressed-down-mode AND :caps-on-mode) OR :caps-pressed-down-mode)

assume we are mapping 1 to 2 with this condition, it should be something like

[:1 :2 [:space-down :caps-on]]
[:1 :2 [:caps-down :!space-down]]
[:1 :2 [:caps-down :!caps-on]]

an example of creating the layer of "button is pressed down"

https://github.com/yqrashawn/yqdotfiles/blob/61dae1e5363a37e01dfca779c64c99639a11b39f/.config/karabiner.edn#L72 this line means: when space is down, set capspace to 1, when space is up, set capspace to 0 and insert space when space pressed alone. It's under the :caps so this only works when caps is 1.

Hi, sorry for the late reply check this rule https://github.com/yqrashawn/yqdotfiles/blob/cdca2d64070234f98963d7b18a5e9aa54fc04ea2/.config/karabiner.edn#L63 remove the #_ prefix to enable it.

This maps caps lock to toggle cap layer between 0/1 in cap layer, ikjl to arrow keys, modifiers+ikjl to modifiers+arrow keys in cap layer, press and hold space space to set capspace to 1 when capspace is 1, ik to page up/down

Thank you for the reply, but as far as I can tell, both of the proposed solutions make use of variables, not layers (if I am wrong here, please correct me), and in my experiments I have found that usage of variables in line with fast pressing of combos, that change these variables, results in "overflow" - keyboard stops responding (probably a karabiner issue, not related to Goku), so if possible, the use of variables is to be avoided - my question is - is there a way to use layers to achieve my desired behavior - when a button is pressed, the layer is ON, when it's not pressed - it is OFF, so I could use layers as conditions for mappings and for turning other layers on (for example, layer "spacebar held" should only turn on when spacebar is held, IF "capslock held" layer is ON). If there is any other alternative to achieve that, besides variables and layers, please do propose?

yqrashawn commented 3 years ago

but as far as I can tell, both of the proposed solutions make use of variables, not layers (if I am wrong here, please correct me)

Layer is implemented by variable. It's just a shortcut for setting variables. I don't think the overflow thing is caused by using variable. It might be related to that your caps_lock is on. Just a guess. Overflow my also caused by input method. I don't have the overflow behavior on my machine using variable and my key repeat is set to 15ms.

yqrashawn commented 2 years ago

feel free to reopen if have any further questions about this issue