モブ沢工房

プログラミングとかLinux関連(特にOSSのグラフィックツール関連)とかレトロゲームとか3Dプリンタやら日曜大工等、色々。

Gdk(pygi)でマウスカーソルを任意位置に動かすには

感動のあまりカキコ!

改造版mypaintのsizechangemode.pyから一部抜粋〜

    def drag_start_cb(self, tdw, event):
        self._ensure_overlay_for_tdw(tdw)
        self._queue_draw_brush()
        # Storing original cursor position and some needed objects.
        dev = event.get_device()
        pos = dev.get_position()
        self._dev = dev
        self._scr = event.get_screen()
        self._ox = pos.x
        self._oy = pos.y
        super(SizechangeMode, self).drag_start_cb(tdw, event)

    def drag_update_cb(self, tdw, event, dx, dy):
        self._ensure_overlay_for_tdw(tdw)
            
        self._queue_draw_brush()
        adj = self.app.brush_adjustment['radius_logarithmic']
        cur_value = adj.get_value() + (dx / 120.0)
        adj.set_value(cur_value)
        self._queue_draw_brush()
        super(SizechangeMode, self).drag_update_cb(tdw, event, dx, dy)

    def drag_stop_cb(self, tdw):
        self._ensure_overlay_for_tdw(tdw)
        self._queue_draw_brush()
        self.start_drag = False
         
        self.base_x = None
        self.base_y = None

        # Reset cursor positon at the start position of dragging.
        Gdk.Device.warp(self._dev, self._scr, self._ox, self._oy)
        super(SizechangeMode, self).drag_stop_cb(tdw)

概要としては

  • event構造体のget_device(), get_screen()が必要。
  • mypaintのdrag_stop_cbにはeventがないので保存しておく
  • 位置はスクリーン座標なのだけど、deviceオブジェクトのget_position()でなんか謎のオブジェクトが得られてそいつの属性x,yがスクリーン座標なので、それを保存しておく。
  • ドラッグ終了時にGdk.Device.warpですっ飛ばす

これで、いままでシフトキー押下で発動するように設定していたオンキャンバスなブラシサイズ変更モード。

これが、サイズ変更でカーソル動いちゃって悲しい感じだったんですが (kritaを真似したのだけど、あっちはちゃんとカーソルが固定される)

ようやく思い通りになりました!

追記:

…と、マウスで実験してみた時は良かったのですが… ペンタブでやってみると、やはりペンタブを動かしてサイズを変更するとカーソルが移動してしまう。 ナンデ? と思ってよくよく考えてみると…

> ペンタブは絶対位置デバイスだから離した瞬間に別の絶対位置に移動している <

という、実にマヌケな結果に… じゃあ、Kritaはどうやってそれを防いでいるのか?

と思ってやってみたら(当たり前ですが)Kritaでも同じ挙動でした(>_<) 記憶が間違っていただけという悲しい結果に。