記事一覧

SHIORIでマウスジェスチャー

SSPのマウスジェスチャーが使いづらい件

SSP/2.01.80-81あたりで追加されたマウスジェスチャーの仕様が不評のようです

そもそもSHIORI側でできそうなことをあえてベースウェアで実装するに至ったのには何か深い理由があるであろうことは想像に難くないですがこれではちょっとあんまりですね。

YAYAで書いてみた

もうちょっと使いやすく。SHIORI側で柔軟に制御することを目標とする。

#define TOLERANCE 10

OnMouseDown
{
  // 右クリック
  if reference[5] == 1 {
    this._isMousedown = 1
    this._startGuesture(reference)
  }
}

OnMouseMove
{
  if this._isMousedown {
    this._progressGesture(reference)
  }
}

OnMouseUp
{
  if this._isMousedown {
    ERASEVAR('this._isMousedown')
    this._stopGuesture(reference)
    return
  }
}

this._startGuesture
{
  this._lastX = _argv[0]
  this._lastY = _argv[1]
  this._directionChain = ''
  this.startX = _argv[0]
  this.startY = _argv[1]
  this._scope = _argv[3]
  this._collision = _argv[4]
}

this._progressGesture
{
  _x = _argv[0]
  _y = _argv[1]
  _dx = _x - this._lastX; if (_dx < 0) { _dx *= -1 }
  _dy = _y - this._lastY; if (_dy < 0) { _dy *= -1 }
  if (_dx < TOLERANCE) && (_dy < TOLERANCE) { return }
  _direction = ''
  if (_dx > _dy) {
    if _x < this._lastX {
      _direction = 'L'
    } else {
      _direction = 'R'
    }
  } else {
    if _y < this._lastY {
      _direction = 'U'
    } else {
      _direction = 'D'
    }
  }
  _lastDirection = SUBSTR(this._directionChain, -1, 1)
  if (_direction != _lastDirection) {
    this._directionChain += _direction
  }
  this._lastX = _x
  this._lastY = _y
}

this._stopGuesture
{
  if this._directionChain != '' {
    "\![raise,OnMouseGestureEx/
      ,%(this._scope)/
      ,%(this._lastX)%(CHR(1))%(this._lastY)/
      ,%(_argv[4])/
      ,%(this.startX)%(CHR(1))%(this.startY)/
      ,%(this._collision)/
      ,%(this._directionChain)]\e"
  }
  ERASEVAR('this._scope')
  ERASEVAR('this._collision')
  ERASEVAR('this._lastX')
  ERASEVAR('this._lastY')
  ERASEVAR('this.startX')
  ERASEVAR('this.startY')
  ERASEVAR('this._directionChain')
}

OnMouseGestureEx
{
  _action = ''
  if reference[0] == 0 {
    case reference[5] {
    when 'L' { _action = '戻る' }
    when 'R' { _action = '進む' }
    when 'D' { _action = '新窓' }
    when 'DR' { _action = '閉じる' }
    when 'UD' { _action = '更新' }
    when 'UDUDRLRLDLUR' { _action = 'エターナルフォースブリザード' }
    others { _action = '未定義' }
    }
    '\0\_q' + reference[5] + ' : ' + _action + '\_q\e'
  }
}

参考にしたもの

ここまで書いて何故か動かなかった。
よく調べてみたらSSPではOnMouseDownの後はOnMouseMoveが通知されないらしい(´・ω・`)

大人しくOnMouseGesture使えってことですね。

09/06/29 追記

SSP/2.01.82でOnMouseMoveが通知されるようになりましたね。
昨日書いたコードに間違いがあったので修正して試したところ、エターナルフォースブリザードが打てるようになりました。
ありがとうございます。

OnMouseGestureを使わない上のコードの使い方

  • TOLERANCEという所を変えることで感度を調整できます。
  • OnMouseGestureExという独自イベントを実装していますが、OnMouseGestureとの違いは最後に一度しか通知されない点、reference[5]に今までの軌跡がまとめて通知される点です。

華和梨で書いてみた

YAYAで書いたものと機能は全く一緒です。

TOLERANCE : 10

event.OnMouseDown : $(
  if $[ $(.get System.Request.Reference5[0]) == 1 ] $(
    .setstr this._isMousedown 1;
    .entry this._startGuesture;
  );
)

event.OnMouseMove : $(
  if $[ ${this._isMousedown} == 1 ] $(
    .entry this._progressGesture;
  );
)

event.OnMouseUp : $(
  if $[ ${this._isMousedown} == 1 ] $(
    .clear this._isMousedown;
    .entry this._stopGuesture;
  );
)

this._startGuesture : $(
  .setstr this._lastX $(.get System.Request.Reference0[0]);
  .setstr this._lastY $(.get System.Request.Reference1[0]);
  .clear this._directionChain;
  .setstr this.startX $(.get System.Request.Reference0[0]);
  .setstr this.startY $(.get System.Request.Reference1[0]);
  .setstr this._scope $(.get System.Request.Reference3[0]);
  .setstr this._collision $(.get System.Request.Reference4[0]);
)

this._progressGesture : $(
  .setstr @x $(.get System.Request.Reference0[0]);
  .setstr @y $(.get System.Request.Reference1[0]);
  .setstr @dx $[ ${@x} - ${this._lastX} ];
  .setstr @dy $[ ${@y} - ${this._lastY} ];
  if $[ ${@dx} < 0 ] $(
    .setstr @dx $[ ${@dx} * (-1) ];
  );
  if $[ ${@dy} < 0 ] $(
    .setstr @dy $[ ${@dy} * (-1) ];
  );
  if $[ !((${@dx} < ${TOLERANCE}) && (${@dy} < ${TOLERANCE})) ] $(
    .clear @direction;
    if $[ ${@dx} > ${@dy} ] $(
      if $[ ${@x} < ${this._lastX} ] $(
        .setstr @direction L;
      ) else $(
        .setstr @direction R;
      );
    ) else $(
      if $[ ${@y} < ${this._lastY} ] $(
        .setstr @direction U;
      ) else $(
        .setstr @direction D;
      );
    );
    .setstr @lastDirection $(.substr ${this._directionChain} -1 1);
    if $[ ${@direction} != ${@lastDirection} ] $(
      .setstr this._directionChain ${this._directionChain}${@direction};
    );
    .setstr this._lastX ${@x};
    .setstr this._lastY ${@y};
  );
)

this._stopGuesture : $(
  if $[ $(.length ${this._directionChain}) > 0 ] $(
    .echo \![raise,OnMouseGestureEx,${this._scope},${this._lastX}$(.chr 1)${this._lastY},$(.get System.Request.Reference4[0]),${this.startX}$(.chr 1)${this.startY},${this._collision},${this._directionChain}]\e;
  );
  .clear this._scope;
  .clear this._collision;
  .clear this._lastX;
  .clear this._lastY;
  .clear this.startX;
  .clear this.startY;
  .clear this._directionChain;
)

event.OnMouseGestureEx : $(
  .clear @action;
  if $[ $(.get System.Request.Reference0[0]) == 0 ] $(
    .setstr @action $(.entry gesture.$(.get System.Request.Reference5[0]) 未定義);
  );
  .echo \0\_q$(.get System.Request.Reference5[0])" ":" "${@action}\_q\e;
)

gesture.L            : 戻る
gesture.R            : 進む
gesture.D            : 新窓
gesture.DR           : 閉じる
gesture.UD           : 更新
gesture.UDUDRLRLDLUR : エターナルフォースブリザード

09/06/30 追記

里々で書く場合はOnMouseMoveで重い処理を行わないように注意が必要です。
イベント通知間隔がOnSecondChangeの比ではないので、ssu.dllなどのSAORI呼び出しも使わないようにしましょう。

里々で書いてみた

YAYAで書いたものと機能は全く一緒です。
ssu.dllを一切使わず高速です。
Mc145-1以降のバージョンの里々で動作します。

@TOLERANCE
10

@OnMouseDown
(
【タブ】when
【タブ】,(R5)==1
【タブ】,(
【タブ】【タブ】set
【タブ】【タブ】,this._isMousedown
【タブ】【タブ】,1
【タブ】)(
【タブ】【タブ】call
【タブ】【タブ】,this._startGuesture
【タブ】)
)

*OnMouseMove
>this._progressGesture【タブ】(call,this._isMousedown)==1

@OnMouseUp
(
【タブ】when
【タブ】,(call,this._isMousedown)==1
【タブ】,(
【タブ】【タブ】set
【タブ】【タブ】,this._isMousedown
【タブ】【タブ】,
【タブ】)(
【タブ】【タブ】call
【タブ】【タブ】,this._stopGuesture
【タブ】)
)

@this._startGuesture
(set,this._lastX,(R0))φ
(set,this._lastY,(R1))φ
(set,this._directionChain,)φ
(set,this.startX,(R0))φ
(set,this.startY,(R1))φ
(set,this._scope,(R3))φ
(set,this._collision,(R4))

*this._progressGesture
$x【タブ】(R0)
$y【タブ】(R1)
$dx=(x)-(when,(変数「this._lastX」の存在),(this._lastX),0)
$abs_dx=(dx)*(-1)
$dx【タブ】(when,(dx)<0,(abs_dx),(dx))
$dy=(y)-(when,(変数「this._lastY」の存在),(this._lastY),0)
$abs_dy=(dy)*(-1)
$dy【タブ】(when,(dy)<0,(abs_dy),(dy))
$dummy【タブ】(when,(dx)<(TOLERANCE)&&(dy)<(TOLERANCE),,(call,this._progressGestureNext))

@this._progressGestureNext
(
【タブ】when
【タブ】,(dx)>(dy)
【タブ】,(
【タブ】【タブ】when
【タブ】【タブ】,(x)<(this._lastX)
【タブ】【タブ】,(set,direction,L)
【タブ】【タブ】,(set,direction,R)
【タブ】),(
【タブ】【タブ】when
【タブ】【タブ】,(y)<(this._lastY)
【タブ】【タブ】,(set,direction,U)
【タブ】【タブ】,(set,direction,D)
【タブ】)
)(
【タブ】when
【タブ】,(direction)!=(call,lastDirection)
【タブ】,(set,this._directionChain,(call,this._directionChain)(direction))
)(
【タブ】set
【タブ】,lastDirection
【タブ】,(direction)
)(
【タブ】set
【タブ】,this._lastX
【タブ】,(x)
)(
【タブ】set
【タブ】,this._lastY
【タブ】,(y)
)

@this._stopGuesture
(
【タブ】when
【タブ】,(変数「this._directionChain」の存在)
【タブ】,(call,sendOnMouseGestureEx)\e
)(
【タブ】call
【タブ】,clearMouseGestureParameter
)
@sendOnMouseGestureEx
\![raise,OnMouseGestureEx,(call,this._scope),(call,this._lastX)(バイト値,1)(call,this._lastY),(R4),(call,this.startX)(バイト値,1)(call,this.startY),(call,this._collision),(call,this._directionChain)]
@clearMouseGestureParameter
(set,this._scope,)φ
(set,this._collision,)φ
(set,this._lastX,)φ
(set,this._lastY,)φ
(set,this.startX,)φ
(set,this.startY,)φ
(set,this._directionChain,)φ
(set,x,)φ
(set,y,)φ
(set,dx,)φ
(set,dy,)φ
(set,abs_dx,)φ
(set,abs_dy,)φ
(set,direction,)φ
(set,lastDirection,)

@OnMouseGestureEx
(
【タブ】when
【タブ】,(R0)==0
【タブ】,(
【タブ】【タブ】when
【タブ】【タブ】,(単語群「gesture.(R5)」の存在)
【タブ】【タブ】,(
【タブ】【タブ】【タブ】set
【タブ】【タブ】【タブ】,action
【タブ】【タブ】【タブ】,(call,gesture.(R5))
【タブ】【タブ】),(
【タブ】【タブ】【タブ】set
【タブ】【タブ】【タブ】,action
【タブ】【タブ】【タブ】,未定義
【タブ】【タブ】)
【タブ】)\0\_q(R5) : (action)\_q\e(set,action,)
)
@gesture.L
戻る
@gesture.R
進む
@gesture.D
新窓
@gesture.DR
閉じる
@gesture.UD
更新
@gesture.UDUDRLRLDLUR
エターナルフォースブリザード

【タブ】は適宜Tabに置き換えて使用してください。