ncursesではマウスの操作を検知できるらしい.ただしSVr4以前とか4.4BSD以前ではできないようだ.
マウスイベント
バグ
マウスイベントの検知
座標
クリックの検知
サンプル
マウスイベント
マウス操作はマウスイベントとして検知される.デフォルトではこの機能はOFFとなっている.これを有効にするには,
mmask_t mousemask(mmask_t newmask, mmask_t *oldmask);
を実行する.第一引数には検知するマウスイベントのマスクを指定する.例えば
BUTTON1_PRESSED
とすればボタン1(左ボタン)が押されたというマウスイベントを検知できるようになる.また,第一引数に0を指定するとマウスイベントの検知がOFFになる.第二引数は古いマウスイベントのマスクを格納する変数を指定する.これが不要ならNULLを指定する.
バグ
man mouseのBUGSによるとxtermでマウスイベントを検知するためには,以下の条件が必要らしい.
cbreakモードになっている(wmousemaskでマウスイベント検知をONにする場合).
キーパッドが有効(なんかマウスイベントをファンクションキーとして扱ってしまうらしい).
terminfoでkmousの値が”\E[M”になっている必要がある.
環境変数$TERMが”xterm”を含むかterminfoでkmousが定義されている.
なんか移植性が心配な雰囲気だ.
マウスイベントの検知
マウスイベントの検知には文字入力と同様getch,wgetchを使用する.その返り値はマウスイベントであればKEY_MOUSEとなる.このとき
int getmouse(MEVENT *event);
とするとMEVENT構造体にマウスイベントの値がセットされる.MEVENT構造体は
typedef struct
{
short id; /* 複数のデバイスを区別するID(?) */
int x, y, z; /* イベント位置(?) */
mmask_t bstate; /* ボタンの状態 */
}
MEVENT;
となっているらしい.zがよくわからない.ungetchと同様ungetmouseでマウスイベントを入力キューに返すことができるらしい.
座標
特に指定しなければ,マウスイベントはmousemaskで指定したボタンが押されたとか離されたということしか検知しない.マウスイベントを検知したとき,マウスの座標をしりたければmousemaskでREPORT_MOUSE_POSITIONを渡す.例えばボタン1の押下を検知し,その座標を知りたいときは
mousemask(BUTTON1_PRESSED | REPORT_MOUSE_POSITION, NULL);
とする.また,stdscrでの座標からスクリーンでの座標に変換するには
bool mouse_trafo(int* pY, int* pX, bool to_screen);
を使用する.このへんはslk_…関数に関係があるらしい(man slk参照).
クリックの検知
マウスのクリックやダブルクリックはmousemask関数の第一引数にBUTTON1_PRESSEDやBUTTON1_RELEASEDを指定して実装出来そうだが,BUTTON1_CLICKEDやBUTTON1_DOUBLE_CLICKED等を指定するだけで検知することができる.で,ボタン押下とボタン離しでボタンクリックやダブルクリックを実装するときをイメージすると,ボタンが押されてから何秒以内にボタンを離せばクリックとするのかを指定する必要がある気がして来る.これを指定するのが,
int mouseinterval(int erval);
である.ボタンを押してから指定した秒数以内にボタンを離せばクリックと判定される.引数に-1を指定すると現在の値が返される.
サンプル
なんか細かいところはよくわからないが,とにかくサンプルを作成してみた.このサンプルはマウスで左クリックした場所に”“を書き,右クリックした場所に” “を書く(すなわち”“が書いてあればそれを消す).
#include <stdio.h>
#include <stdlib.h>
#include <curses.h>
#include <unistd.h>
int main(void)
{
MEVENT event;
int input;
if(initscr() == NULL){
fprintf(stderr, "initscr failure\n");
exit(EXIT_FAILURE);
}
/* �ޥ������٥�Ȥ��Τ���ˤϰʲ���ɬ�� */
cbreak();
keypad(stdscr, TRUE);
/* ���Τ���ޥ������٥�Ȥ���� */
mousemask(BUTTON1_PRESSED | /* ���ܥ��� */
BUTTON3_PRESSED | /* ���ܥ��� */
REPORT_MOUSE_POSITION, /* ��ɸ�μ��� */
NULL);
refresh();
/* 'q'�����Ϥ��줿�齪λ */
while((input = mvwgetch(stdscr, 0, 0)) != 'q'){
/* �ޥ������٥�Ȥξ�� */
if(input == KEY_MOUSE){
mvprintw(2, 5, "mouse event");
/* MEVENT��¤�Τ����� */
if(getmouse(&event) != OK){
mvprintw(3, 5, "getmouse failure");
continue;
}
/* MEVENT��¤�Τ�x,y,z��ɽ�� */
mvprintw(3, 5, "x = %d, y = %d, z = %d", event.x, event.y, event.z);
/* ���ܥ����ʤ�"*"��ޥ����ݥ��ξ���ɽ�� */
if(event.bstate == BUTTON1_PRESSED){
mvprintw(event.y, event.x, "*");
}
/* ���ܥ����ʤ�" "��ޥ����ݥ��ξ���ɽ�� */
else if(event.bstate == BUTTON3_PRESSED){
mvprintw(event.y, event.x, " ");
}
refresh();
}
/* �ޥ������٥�ȤǤʤ���� */
else{
mvprintw(2, 5, "not mouse event %c", input);
}
}
endwin();
exit(EXIT_SUCCESS);
}