Skip to content
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

Cycle items and paste with single hotkey #1948

Closed
gerardbosch opened this issue Mar 29, 2022 · 12 comments
Closed

Cycle items and paste with single hotkey #1948

gerardbosch opened this issue Mar 29, 2022 · 12 comments
Labels
command feature New feature request

Comments

@gerardbosch
Copy link

Is your feature request related to a problem? Please describe.
No, it is more related to the user experience, and to improve usability for a quite common use case of quickly pasting sequential items 😃

Describe the solution you'd like

Hi @hluk, did you have the chance to check this in 'Discussions'? #1893
I'm opening the feature request here, just in case you missed that.

Thanks a lot 🙏!

@gerardbosch gerardbosch added the feature New feature request label Mar 29, 2022
@kireta
Copy link

kireta commented Apr 3, 2022

Would be great if implemented!

@hluk
Copy link
Owner

hluk commented Apr 4, 2022

Sounds quite handy. The functionality can be added to CopyQ with the following command (here is how to add the command to CopyQ):

[Command]
Command="
    copyq:
    // Show/focus the main window if not focused,
    // otherwise cycle through items and paste selected
    // when the shortcut is released.
    if (focused()) {
        const sel = ItemSelection().current();
        const rows = sel.rows();
        if (rows.length > 0) {
            selectItems(rows[0] + 1);
        } else {
            selectItems(0);
        }
    } else {
        show();
        // Wait for shortcut modifiers to be released
        // or the main window to lose focus.
        while (focused() && queryKeyboardModifiers().length > 0) {
            sleep(20);
        }
        if (focused()) {
            copy();
            hide();
            paste();
            selectItems(0);
        }
    }"
GlobalShortcut="ctrl+;"
Icon=\xf1b8
InMenu=true
IsGlobalShortcut=true
Name=Cycle Items

@gerardbosch
Copy link
Author

gerardbosch commented Apr 6, 2022

Hi @hluk! Many thanks to have a look on this :)

I've been trying it and I found a couple problems with the script.

  1. The pasted element is not moved to the top, what defeats the purpose of sequential copy like:
    Copy the words first second third and then paste it in order by doing Ctrl-;;; 3 times in a row (e.g. in different fields of a web form).

    I tried to browse the script API to see how should the copy() make the item to the top (maybe using select() or other function than copy??), but I was not able to make it work 😕

  2. If I issue fast the shortcut Ctrl-; and release, sometimes it blinks the copyq window and pastes the first item; and sometimes it opens the copyq window and does nothing (and I get an exception notification).

    The thing is that when I make a single press of Ctrl-; and release, I would expect the copyq opens and nothing else, just like regular 'Show main window' would do.
    In contrast, if I press Ctrl-;; and release I would expect the following:

    • copyq opens on first ; release
    • the second element is highlighted as I press and release the second ; (still holding Ctrl)
    • the second item is pasted and copyq hidden as soon as I release Ctrl.
  3. The idea was to use the same shortcut (Ctrl-; in this case) to both 'Show main window' (single press) and 'Cycle to items' (multiple press). I had to disable the 'Show main window' shortcut to let the script to take the control. I think that this would not be an issue as I'm understanding that the "cycle script" would work as a more powerful replacement of the default 'Show main window' command. I don't want to have 2 hotkeys but one that serves both purposes :)


Would it be possible you help me to achieve (1) and to understand/debug (2)?

Side question, if this finally works fine, do you think it could be added as default command in copyq as "Show main window/cycle items" behaviour?

Clarifications

  • I'm using the Ctrl-; hotkey as ; is just convenient to me - it is placed on home row on US keyboard.
  • I'm testing on Linux with CopyQ 6.0.1

Thank you! 😃

@hluk
Copy link
Owner

hluk commented Apr 14, 2022

The following command should hopefully work as you describe:

[Command]
Command="
    copyq:
    // Show/focus the main window if not focused,
    // otherwise cycle through items and paste selected
    // when the shortcut is released.
    const selectedRowOption = 'cycleItemsSelectedRow'

    if (focused()) {
        const sel = ItemSelection().current();
        const rows = sel.rows();
        const row = rows.length > 0 ? rows[0] + 1 : 0;
        settings(selectedRowOption, row)
        selectItems(row);
    } else {
        settings(selectedRowOption, 0)
        show();
        
        // Wait for shortcut modifiers to be released.
        while (queryKeyboardModifiers().length > 0) {
            sleep(20);
        }
        
        const row = settings(selectedRowOption)
        if (row != 0) {
            select(row)
            hide()
            paste()
        }
    }"
GlobalShortcut="ctrl+;"
Icon=\xf1b8
InMenu=true
IsGlobalShortcut=true
Name=Cycle Items

@gerardbosch
Copy link
Author

That is AWESOME! 👏👏👏
You totally made my day ✨😊

I'm closing, thanks a lot!

@hluk
Copy link
Owner

hluk commented Apr 16, 2022

This is now available in the command repository: https://github.com/hluk/copyq-commands/tree/master/Global#cycle-items

@Gitoffthelawn
Copy link
Contributor

The following command should hopefully work as you describe:

[Command]
Command="
    copyq:
    // Show/focus the main window if not focused,
    // otherwise cycle through items and paste selected
    // when the shortcut is released.
    const selectedRowOption = 'cycleItemsSelectedRow'

    if (focused()) {
        const sel = ItemSelection().current();
        const rows = sel.rows();
        const row = rows.length > 0 ? rows[0] + 1 : 0;
        settings(selectedRowOption, row)
        selectItems(row);
    } else {
        settings(selectedRowOption, 0)
        show();
        
        // Wait for shortcut modifiers to be released.
        while (queryKeyboardModifiers().length > 0) {
            sleep(20);
        }
        
        const row = settings(selectedRowOption)
        if (row != 0) {
            select(row)
            hide()
            paste()
        }
    }"
GlobalShortcut="ctrl+;"
Icon=\xf1b8
InMenu=true
IsGlobalShortcut=true
Name=Cycle Items

This is very useful. Thank you. I have 1 issue and 2 requests:

The issue is that often I get a notification stating Data Copied <EMPTY> when it's at the last CopyQ item.

The first request is making it wrap around to the first item after the last item.

The second request may be quite challenging or maybe even impossible. How about another version in which, when reaching the last item, pressing the shortcut key again moves up one item in the list. For example, let's say we have the following items in the list:

one
two
three

If you hold down the ctrl key, and tap the semicolon once, you get one. Keep holding the ctrl key and press the semicolon again, and you get two. Keep holding the ctrl key and press the semicolon again, and you get three. Keep holding the ctrl key and press the semicolon again, and you get two. Keep holding the ctrl key and press the semicolon again, and you get one. Ad infinitum...

@hluk
Copy link
Owner

hluk commented Apr 24, 2022

I fixed the command so it wraps the selection around: This is now available in the command repository: https://github.com/hluk/copyq-commands/tree/master/Global#cycle-items

@Gitoffthelawn Your other idea with back-and-forth selection would be possible using another option for the current selection direction:

[Command]
Command="
    copyq:
    // Pops up the main window (if the shortcut is pressed once), cycles through items
    // (if the shortcut is pressed again) and pastes selected item when the shortcut
    // is released.
    const selectedRowOption = 'cycleItemsSelectedRow'
    const selectedTabOption = 'cycleItemsSelectedTab'
    const selectDirection = 'cycleItemsSelectDirection'

    if (focused()) {
        const sel = ItemSelection().current();
        const rows = sel.rows();
        var direction = Number(settings(selectDirection))
        var row = rows.length > 0 ? (rows[0] + direction) : 0;
        if (row < 0 || row >= length()) {
            direction = -direction
            settings(selectDirection, direction)
            row = rows[0] + direction
        }
        settings(selectedRowOption, row)
        settings(selectedTabOption, selectedTab())
        selectItems(row);
    } else {
        settings(selectedRowOption, -1)
        settings(selectDirection, 1)
        show();

        // Wait for shortcut modifiers to be released.
        while (queryKeyboardModifiers().length > 0) {
            sleep(20);
        }

        const row = settings(selectedRowOption)
        if (row != -1) {
            tab(settings(selectedTabOption))
            select(row)
            hide()
            paste()
        }
    }"
GlobalShortcut="ctrl+;"
Icon=\xf1b8
InMenu=true
IsGlobalShortcut=true
Name=Cycle Items

@Gitoffthelawn
Copy link
Contributor

Thanks so much Lukas! I look forward to trying what you created.

BTW, any idea why the original will often display a notification stating Data Copied <EMPTY> when its reached the last CopyQ item?

@hluk
Copy link
Owner

hluk commented Apr 25, 2022

BTW, any idea why the original will often display a notification stating Data Copied <EMPTY> when its reached the last CopyQ item?

Guessing it copied empty data (from an out-of-builds item index).

@ghost
Copy link

ghost commented Nov 21, 2022

This deserves its own place in CopyQ's manual. the custom command neatly replicates how Ditto on Windows handles with clipboard cycling (Alt-Tab switcher like cycling) and it's one of the small QoL details I missed most on Linux.

@gerardbosch
Copy link
Author

I'm totally delighted with this feature <3 Using it for months now and super happy. So thanks again for your so quick reply with the command @hluk I hope many others enjoy/found it as well =)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
command feature New feature request
Projects
None yet
Development

No branches or pull requests

4 participants