{"version": "https://jsonfeed.org/version/1", "title": "/dev/posts/ - Tag index - x11", "home_page_url": "https://www.gabriel.urdhr.fr", "feed_url": "/tags/x11/feed.json", "items": [{"id": "http://www.gabriel.urdhr.fr/2020/04/11/push-to-talk-in-any-application/", "title": "Push-to-talk in any application", "url": "https://www.gabriel.urdhr.fr/2020/04/11/push-to-talk-in-any-application/", "date_published": "2020-04-11T00:00:00+02:00", "date_modified": "2020-04-11T00:00:00+02:00", "tags": ["computer", "unix", "gui", "pulseaudio", "x11", "covid-19"], "content_html": "

Some scripts I wrote to enable system-wide push-to-talk\n(for X11 and PulseAudio).\nSome people might find it for the ongoing lockdown.

\n

Some VoIP software have builtin support for push-to-talk.\nIn this mode, a global keyboard hotkey must be be held while speaking.\nThis is quite useful when in a noisy environment\nand/or with suboptimal mics.

\n

Some programs with support for this:

\n\n

Most programs don't support this.\nThis is especially true for browser-based VoIP software because as there is currently\nnot web API (AFAIU) ro register a global keyboard hotkey1.

\n

So I wrote two Python scripts for PulseAudio.

\n

Push-to-talk

\n

The first one\nimplements push-to-talk based on some keyboard key.\n(i.e. you have to hold the key while you are talking):

\n
pushtotalk --key \"Home\"\n
\n\n\n

It's intended for PulseAudio\nand X11 but it should be quite easy to adapt this to other sound and GUI systems.

\n

Toggle audio source

\n

The second one\njust toggles the mute state of the default PulseAudio source\nand provides a visual feedback (notification).\nIt's intended to be bound to some global keyboard hotkey.

\n

For example using a script\nbased on keybinder:

\n
keybinder \"<Control>m\" pulse-mute-toggle\n
\n\n\n

Simply toggling the audio source can be done with:

\n
pactl set-sink-mute @DEFAULT_SOURCE@ toggle\n
\n\n\n

Getting the notification of the state is important because otherwise you might\nend being in the wrong state.\nThere is no pactl get-sink-mute @DEFAULT_SOURCE@ command\nwhich is why it's not an absolutely straightforward shell script2.

\n
\n
\n
    \n
  1. \n

    This is why this feature is apparently available on the native Discord application\nbut not on the web one.\u00a0\u21a9

    \n
  2. \n
  3. \n

    It can be done by:

    \n
      \n
    • parsing the output of pacmd list-sources or similar (which is cumbersome);
    • \n
    • relying on the native protocol;
    • \n
    • use the PulseAudio D-Bus interface.
    • \n
    \n

    I decided to use the D-Bus interface\n(which is sadly not enabled by default).\u00a0\u21a9

    \n
  4. \n
\n
"}, {"id": "http://www.gabriel.urdhr.fr/2014/09/25/filtering-the-clipboard/", "title": "Filtering the clipboard using UNIX filters", "url": "https://www.gabriel.urdhr.fr/2014/09/25/filtering-the-clipboard/", "date_published": "2014-09-25T00:00:00+02:00", "date_modified": "2014-09-25T00:00:00+02:00", "tags": ["computer", "x11", "unix", "cms", "hmtl"], "content_html": "

I had a few Joomla posts that I wanted to clean up semi-automatically.\nHere are a few scripts, to pass the content of the clipboard (or the\ncurrent selection) through a UNIX filter.

\n

Filter for cleaning HTML posts

\n

Cleaning up the (HTML) content of the posts was quite time consuming\nand very repetitive:

\n\n

Most of the job could be done by a script\n(cleanup_html):

\n
#!/usr/bin/env ruby\n# Remove some crap from HTMl snippets.\n\nrequire \"nokogiri\"\n\nif (ARGV[0])\n  html = File.read(ARGV[0])\nelse\n  html = $stdin.read\nend\ndoc = Nokogiri::HTML::DocumentFragment.parse html\n\n# Remove 'style':\ndoc.css(\"*[style]\").each do |node|\n  style = node.attribute(\"style\")\n  node.remove_attribute(\"style\")\n  $stderr.puts \"Removed style: #{style}\\n\"\nend\n\n# Remove useless span:\ndoc.css(\"span\").each do |span|\n  $stderr.puts \"Unwrapping span: #{span}\\n\"\n  span.children.each do |x|\n    span.before(x)\n  end\n  span.remove\nend\n\n# Split paragraphs on <br/>:\ndoc.css(\"p > br\").each do |br|\n  p = br.parent\n\n  # Clone\n  new_p = p.document.create_element(\"p\")\n  p.children.take_while{ |x| x!=br }.each do |x|\n    new_p.add_child x\n  end\n  p.before(new_p)\n\n  br.remove\nend\n\n# Remove empty paragraphs:\ndoc.css(\"p\").each do |node|\n  if node.element_children.empty? && /\\A *\\z/.match(node.inner_text)\n    node.remove\n  end\nend\n\nprint doc.to_html\n
\n\n\n

Filtering the clipboard or selection

\n

I wanted to do a semi-automatic update in order to have feedback on\nwhat was happening and fix the remaining issues straightaway. To do\nthis, the filter can be applied on the X11 clipboard:

\n
#!/bin/sh\nxclip -out -selection clipboard | filter_html | xclip -in -selection clipboard\n
\n\n\n

It is even possible to do it on the current selection:

\n
#!/bin/sh\nsleep 0.1\nxdotool key control+c\nsleep 0.1\nxclip -out -selection clipboard | filter_htm | xclip -in -selection clipboard\nxdotool key control+v\n
\n\n\n

This second script is quite hackish but it kind of works:

\n\n

This can be generalized with this script (gui_filter):

\n
#!/bin/sh\n\nmode=\"$1\"\nshift\n\ncase \"$mode\" in\n    primary | seconday | clipboard)\n        xclip -out -selection \"$mode\" | command \"$@\" | xclip -in -selection \"$mode\"\n        ;;\n    selection)\n        # This is an horrible hack.\n        # It only works for C-c/C-v keybindings.\n        sleep 0.1\n        xdotool key control+c\n        sleep 0.1\n        xclip -out -selection clipboard | command \"$@\" | xclip -in -selection clipboard\n        xdotool key control+v\n        ;;\nesac\n
\n\n\n

Called with:

\n
# Clean the HTMl markup in the clipboard:\ngui_filter clipboard html_filter\n\n# Base-64 encode the current selection:\ngui_filter selection base64\n\n# Base-64 decode the current selection:\ngui_filter selection base64 -d\n
\n\n\n

Binding it to a key

\n

Now we can bind this command to a temporary global hotkey with this\nscript based on the keybinder library:

\n
#!/usr/bin/env python\n# Bind a global hotkey to a given command.\n# Examples:\n#   keybinder '<Ctrl>e' gui_filter selection base64\n#   keybinder '<Ctrl>X' xterm\n\nimport sys\nimport gi\nimport os\nimport signal\n\ngi.require_version('Keybinder', '3.0')\nfrom gi.repository import Keybinder\nfrom gi.repository import Gtk\n\ndef callback(x):\n    os.spawnvp(os.P_NOWAIT, sys.argv[2], sys.argv[2:])\n\nsignal.signal(signal.SIGINT, signal.SIG_DFL)\nGtk.init()\nKeybinder.init()\nKeybinder.bind(sys.argv[1], callback);\nGtk.main()\n
\n\n\n

The kotkey is active as long as the keybinder process is not killed.

\n

Conclusion

\n
keybinder '<Ctrl>e' gui_filter selection html_filter\nkeybinder '<Ctrl>e' gui_filter selection kramdown\nkeybinder '<Ctrl>e' gui_filter selection cowsay\nkeybinder '<Ctrl>e' gui_filter selection sort\n\n# More dangerous:\nkeybinder '<Ctrl>e' gui_filter clipboard bash\nkeybinder '<Ctrl>e' gui_filter clipboard ruby\nkeybinder '<Ctrl>e' gui_filter clipboard python\n
\n\n\n

Other solutions

\n

With Emacs

\n

On Emacs, the shell-command-on-region command (bound to\nM-|) can be used to pass the current selection to a given\ncommand: by default the output of the command will be pushed on the\nring buffer. Alternatively, C-u M-| can be used to replace\nthe selection.

\n

With Vim

\n

The ! command can be used to transform a given part of the\ncurrent buffer through a shell filter.

\n

With atom

\n

Atom can replace filter the current selection through a pipe\nwith the pipe package.

"}]}