Unityサウンドインジケーターでキーボードショートカットをハングさせる方法

私は、この投稿に興味を持つ多くの人と同様に、便利なホットキーとさまざまなソフトウェアとの統合のためのさまざまなパンのためのUnityシェルが大好きです。

これらの利点の1つは、mpris2インターフェイスをサポートするプレーヤーをサウンドインジケーターに統合することです。

このサウンドインジケータが何であるか知らない人のために
これは、時計のすぐ左にあるインジケーターパネルにスピーカーがあるバッジです。

画像画像






注目に値するのは、プレーヤーのように振る舞うことができるWebアプリケーションもこのすばらしいリストに含まれていることです。 そして、すべてがクールになりますが、この魅力は、開発者の奇妙な気まぐれによって、音量レベルを変更することを除いて、ホットキーをサポートしていません。



このすべてがどのように機能するかを読みたくない人は、記事の終わりに近づくか、直接githubに進むことができます。 他の人に頼みます。



どうやってそのような企業を始めることができますか?



もちろん、まずはグーグルで検索する価値がありますが、奇妙なことに、わかりやすい結果は得られません-特定のプレーヤー向けのいくつかのソリューションと、インジケーターが開いているときにホットキーが機能しないというバグへのリンクです。

次の明らかなステップは、このコンポーネントのソースを検索して、欠落している機能をファイルで仕上げることです。 判明したように、 公式の統一Webサイトには、これらのソースコードを十分に迅速に取得するために必要なすべてのものがあります。 これを行うには、 「関与する」セクションに進みます。これには、すべての作業に関与する必要があると判断したためです。 次に、 「開発」セクションに進みます。 ソースコンポーネント自体も必要です。標準コンポーネントを完成させたいので、パスは「共通コンポーネント」セクションにあります。 待望のインジケータを実際に見つける場所はここにありますが、何らかの理由で「サウンドメニュー」という名前で表示されますが、システムの他の部分では単にインジケータと呼ばれていますが、まあまあです。



のこぎりで、すぐに切ります



ソースをダウンロードしてください...
bzr branch lp:indicator-sound
      
      





共有は、valaで完全にやや少ししか行われません。 最初の衝動は、ホットキーをすばやくすばやくインストールし、正しい人の仕事の結果を再コンパイルして使用することです。 ただし、これらのキーの構成を記述し、その形式を把握し、ホットキーをグローバルに処理する方法を把握し、システムによってインストールされたホットキーとの競合を解決し、それをvalaに書き込む方法を把握し、ソースをもう少し強制的に読み取る必要があるという考えに触発された退屈ひたすら一貫して。



何がありますか



予想どおり、私たちの興味を引くかもしれないソースはすべて、srcディレクトリにあります。 main.valaでいつものように始めましょう:

main.vala
 [CCode (cheader_filename="libintl.h", type="char *")] extern unowned string bind_textdomain_codeset (string domainname, string codeset); static int main (string[] args) { bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8"); Intl.setlocale (LocaleCategory.ALL, ""); Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.GNOMELOCALEDIR); Notify.init ("indicator-sound"); var service = new IndicatorSound.Service (); return service.run (); }
      
      







ここでは、これはトレイアイコンを提供するある種のクラシックUIアプリケーションではなく、特定のサービスであることがわかります。

  var service = new IndicatorSound.Service ();
      
      





これはサービスであるため、レンダリングと管理に必要なすべてのものが特定のインターフェイスを介して利用できることを意味します。詳しくは、service.valaを見てみましょう。 フォームの行:

 //... void bus_acquired (DBusConnection connection, string name) {//...} //... void name_lost (DBusConnection connection, string name) {//...} //...
      
      





間違いなく、彼らはここに特定のバス、すなわちD-Busが関係していることを示唆しています。 グーグルで流ogに話すと、これは非常にオブジェクト指向のインターフェイスであり、 コンソールから取得でき 、さらにさまざまなサービスの相互作用を監視できることが理解できます 。 次のコマンドでインストールできるqdbusviewerなどのGUIユーティリティもあります。
 sudo apt-get install qdbus-qt5
      
      





さらに、メインで呼び出されるrunメソッドの内部を調べる価値があります。

  public int run () { if (this.loop != null) { warning ("service is already running"); return 1; } Bus.own_name (BusType.SESSION, "com.canonical.indicator.sound", BusNameOwnerFlags.NONE, this.bus_acquired, null, this.name_lost); this.loop = new MainLoop (null, false); this.loop.run (); return 0; }
      
      





own_nameメソッドに関するドキュメントには、わかりにくいものが記載されていますが、同じバスに登録しているように見えます。



実験する時間です



gdbusコマンドには、優れたマルチ通信イントロスペクトメソッドがあります。

システムの目を通して私たちのサービスを見てみましょう
 $ gdbus introspect --session --dest com.canonical.indicator.sound --object-path \ /com/canonical/indicator/sound node /com/canonical/indicator/sound { interface org.freedesktop.DBus.Properties { methods: Get(in s interface_name, in s property_name, out v value); GetAll(in s interface_name, out a{sv} properties); Set(in s interface_name, in s property_name, in v value); signals: PropertiesChanged(s interface_name, a{sv} changed_properties, as invalidated_properties); properties: }; interface org.freedesktop.DBus.Introspectable { methods: Introspect(out s xml_data); signals: properties: }; interface org.freedesktop.DBus.Peer { methods: Ping(); GetMachineId(out s machine_uuid); signals: properties: }; interface org.gtk.Actions { methods: List(out as list); Describe(in s action_name, out (bgav) description); DescribeAll(out a{s(bgav)} descriptions); Activate(in s action_name, in av parameter, in a{sv} platform_data); SetState(in s action_name, in v value, in a{sv} platform_data); signals: Changed(as removals, a{sb} enable_changes, a{sv} state_changes, a{s(bgav)} additions); properties: }; node desktop_greeter { }; node phone { }; node desktop { }; };
      
      







このサービスを管理するため、org.gtk.Actionsインターフェースが最も興味深いものです。 理論的には、他の方法でも可能ですが、vkcomプレーヤーで実験することをお勧めします。 次のようなコマンドを実行してみましょう。

 dbus-monitor > monitor.log
      
      





そして、プレーヤーと少しやり取りします。つまり、Play、Pause、Next、Previousを押します。

そして今、私たちはログでアクションの結果を見つけます:
 .... #  ,     ,    ,       method call sender=:1.9 -> dest=:1.19 serial=27912 path=/com/canonical/indicator/sound; interface=org.gtk.Actions; member=Activate string "play.vkcomvkcom.desktop" array [ ] array [ ] ... # : ... #Next method call sender=:1.9 -> dest=:1.19 serial=27918 path=/com/canonical/indicator/sound; interface=org.gtk.Actions; member=Activate string "next.vkcomvkcom.desktop" array [ ] array [ ] ... #Previous method call sender=:1.9 -> dest=:1.19 serial=27918 path=/com/canonical/indicator/sound; interface=org.gtk.Actions; member=Activate string "previous.vkcomvkcom.desktop" array [ ] array [ ] ...
      
      







そして、ポーズはどこにありますか? うーん、しかし、そうではない、現在の状態に応じて、プレイ/一時停止のみがあり、もちろん、それを見つける方法を見つけます。 org.gtk.Actionsに関する前提は完全に成果を上げました。インディケーターを突くときに使用したものとは異なるインターフェース、つまりコンソールを介してアクションを再現してみましょう。

 #Play/Pause gdbus call --session --dest com.canonical.indicator.sound --object-path /com/canonical/indicator/sound \ --method org.gtk.Actions.Activate 'play.vkcomvkcom.desktop' [] {} #Next gdbus call --session --dest com.canonical.indicator.sound --object-path /com/canonical/indicator/sound \ --method org.gtk.Actions.Activate 'next.vkcomvkcom.desktop' [] {} #Previous  .  .. ...
      
      





次のコマンドを実行すると、アクションの完全なリストを見つけることができます。

 gdbus call --session --dest com.canonical.indicator.sound --object-path /com/canonical/indicator/sound --method org.gtk.Actions.List
      
      





それらがどのような原理で形成されているのか、あなたはすでに捕らえていると思います。



実装



かっこいい! はい、確かにこの形式では既に使用することができます-特定のプレーヤーのために...しかし、これは私たちの方法ではありません。

私はあなたのことは知りませんが、通常は複数のプレーヤーがインストールされており、それらすべてを管理したいと思います。 これを行うには、複数のプレイヤーが同時にプレイできるため、「現在の」プレイヤーを切り替えるための何らかのメカニズムを考え出す必要があります。 これを行うために、インジケーターサウンドサービスによって制御されるプレーヤーの完全なリストを取得する方法があれば害はありません。 少しグーグルですが、このリストは特定の「dconf databse」にあり、dconfユーティリティを使用して操作できることを理解するのは簡単です。 やってみますか?

 dconf read /com/canonical/indicator/sound/interested-media-players
      
      





それは非常に読みにくいですか? など:

 dconf read /com/canonical/indicator/sound/interested-media-players | sed -e "s:[],'\[]::g" -e "s:\s:\n:g"
      
      





私たちのすべてを鎮静します 。 それでは、何が「今」を選択するのでしょうか? さて、この問題は次のように解決しました。

コード
 #         UCS_CACHE=~/.cache/unity-control-sound UCS_CURRENT_PLAYER_FILE=$UCS_CACHE/current-player #   UCS_INTERESTED_PLAYERS=`dconf read \ /com/canonical/indicator/sound/interested-media-players \ | sed -e"s:[],'\[]::g" ` #   UCS_PREFFERED_PLAYERS=`dconf read /com/canonical/indicator/sound/preferred-media-players \ | sed -e "s:[],'\[]::g"` mkdir -p $UCS_CACHE touch $UCS_CURRENT_PLAYER_FILE UCS_CURRENT_PLAYER=`cat $UCS_CURRENT_PLAYER_FILE` function initialize-current-player { #          if ! echo $UCS_INTERESTED_PLAYERS | grep -q $UCS_CURRENT_PLAYER ; then #      UCS_CURRENT_PLAYER=`echo $UCS_PREFFERED_PLAYERS | grep -o "^\S*[^.]"` UCS_CURRENT_PLAYER=`echo $UCS_CURRENT_PLAYER | sed "s/\s//g"` echo Current player now is '"'$UCS_CURRENT_PLAYER'"' fi } #    function player-next { initial_player=$UCS_CURRENT_PLAYER for player in $UCS_INTERESTED_PLAYERS do if [ -z "$first_player" ]; then first_player=$player fi if [ "$previous_player" == "$UCS_CURRENT_PLAYER" ]; then UCS_CURRENT_PLAYER=$player break fi previous_player=$player done if [ "$initial_player" == "$UCS_CURRENT_PLAYER" ]; then UCS_CURRENT_PLAYER=$first_player fi echo $UCS_CURRENT_PLAYER > $UCS_CURRENT_PLAYER_FILE } #    function player-previous { initial_player=$UCS_CURRENT_PLAYER for player in $UCS_INTERESTED_PLAYERS do if [ -z "$first_player" ]; then first_player=$player fi if [ "$player" == "$UCS_CURRENT_PLAYER" ]; then UCS_CURRENT_PLAYER=$previous_player fi previous_player=$player done if [ -z "$UCS_CURRENT_PLAYER" ]; then UCS_CURRENT_PLAYER=$previous_player fi echo $UCS_CURRENT_PLAYER > $UCS_CURRENT_PLAYER_FILE }
      
      







どれでもありませんが、プレーヤーを切り替えるためのインターフェイスがあります。 しかし、私はそれがまともに見えるようにしたいと思います、そしてそれは何らかの形でUI上に現れることが望ましいでしょう:

コード
 #,         ,    ,  #,      : UCS_SYSTEM_WIDE_LAUNCHERS_PATH=/usr/share/applications UCS_LAUNCHERS_PATH=~/.local/share/applications #       function player-launcher { name=$1 launcher=$UCS_LAUNCHERS_PATH/$name system_wide_launcher=$UCS_SYSTEM_WIDE_LAUNCHERS_PATH/$name if [ -f "$launcher" ]; then echo $launcher else echo $system_wide_launcher fi } #       function player-display-name { name=$1 launcher=`player-launcher $name` if [ -f "$launcher" ]; then cat $launcher | grep -m 1 "^Name=" \ | sed "s/Name=//" else echo $player | sed "s/.desktop//" fi } #   ,    function current-player-icon { launcher=`player-launcher $UCS_CURRENT_PLAYER` if [ -f "$launcher" ]; then cat $launcher | grep "Icon=" \ | sed "s/Icon=//" fi } #          function show-current-player { echo Curent player '"'$UCS_CURRENT_PLAYER'"' for player in $UCS_INTERESTED_PLAYERS do if [ $player == $UCS_CURRENT_PLAYER ]; then players=$players* fi player_name=`player-display-name $player` players=$players$player_name\\n done icon=`current-player-icon` if ! [ -z $icon ]; then icon="-i $icon" fi echo Icon is "$icon" notify-send "Players:" "$players" $icon -t 1 }
      
      







お気づきかもしれませんが、私はnotify-sendコマンドを使用して、プレーヤーリスト情報を通知として表示しました。 これは、Ubuntuではデフォルトで「-t」フラグがこのコマンドに対して機能せず、通知が表示される間のタイムアウトを示すため、通知が長時間表示されます。 これらの手順を使用してこれを修正できます。 おそらく誰かが言うでしょう-これはUnixの方法ではなく、データの受信とUIへの出力を混在させることに同意しますが、スクリプトの使用を複雑にしないために、私はそれをしました。

上記のgdbusスキルを使用すると、プレーヤー管理機能の残りの部分を簡単に実装できるため、これについて詳しくは説明しません。したがって、最終的に何が起こったかはgithubで確認できます。 それとは別に、現在のトラックに関する情報を収集する実装について言及したいだけです。 判明したプレーヤーの状態に関する情報は、プレーヤーの起動を担当するアクション状態(gtk.Action)に保存されます。 この情報はorg.gtk.Actions.Describeメソッドを使用して取得でき、次のように実行されます。

 gdbus call --session --dest com.canonical.indicator.sound --object-path /com/canonical/indicator/sound \ --method org.gtk.Actions.Describe vkcomvkcom.desktop
      
      





このコマンドの出力には、プレーヤーの現在の状態と、存在する場合は現在のトラックに関する最小限の必要な情報が含まれています。

作業が完了した後は、結果のスクリプトからアクションを引き起こすホットキーを追加するだけです。 このためにCompizConfigを使用しました。 通常の方法ではできませんでした(Ubuntu 13.10)。なぜこれが機能しないのかわかりませんが、すぐに修正されることを願っています。

次のコマンドを使用してCompizConfigをインストールできます。

 sudo apt-get install compizconfig-settings-manager
      
      





すべて次のようになります。

スクリーンショット
画像

画像

画像



それだけです、ご清聴ありがとうございました。



All Articles