This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/windowmanager/intern/wm_event_system.c

471 lines
12 KiB
C
Raw Normal View History

/**
* $Id:
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The Original Code is Copyright (C) 2007 Blender Foundation.
* All rights reserved.
*
*
* Contributor(s): Blender Foundation
*
* ***** END GPL LICENSE BLOCK *****
*/
#include <stdlib.h>
#include <string.h>
#include "DNA_listBase.h"
#include "DNA_screen_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_userdef_types.h" /* U.flag & TWOBUTTONMOUSE */
#include "MEM_guardedalloc.h"
#include "GHOST_C-api.h"
#include "BLI_blenlib.h"
#include "BKE_blender.h"
#include "BKE_global.h"
#include "WM_api.h"
#include "WM_types.h"
#include "wm.h"
#include "wm_window.h"
#include "wm_event_system.h"
#include "wm_event_types.h"
/* ************ event management ************** */
static void wm_event_add(wmWindow *win, wmEvent *event_to_add)
{
wmEvent *event= MEM_callocN(sizeof(wmEvent), "event");
*event= *event_to_add;
BLI_addtail(&win->queue, event);
}
wmEvent *wm_event_next(wmWindow *win)
{
wmEvent *event= win->queue.first;
if(event) BLI_remlink(&win->queue, event);
return event;
}
static void wm_event_free(wmEvent *event)
{
if(event->customdata) MEM_freeN(event->customdata);
MEM_freeN(event);
}
void wm_event_free_all(wmWindow *win)
{
wmEvent *event;
while((event= win->queue.first)) {
BLI_remlink(&win->queue, event);
wm_event_free(event);
}
}
/* ********************* handlers *************** */
void wm_event_free_handlers(ListBase *lb)
{
wmEventHandler *handler;
for(handler= lb->first; handler; handler= handler->next) {
if(handler->op)
MEM_freeN(handler->op);
}
BLI_freelistN(lb);
}
static int wm_eventmatch(wmEvent *winevent, wmKeymapItem *km)
{
if(winevent->type!=km->type) return 0;
if(km->val) /* KM_PRESS, KM_RELEASE */
if(winevent->val!=km->val-1) return 0;
if(winevent->shift!=km->shift) return 0;
if(winevent->ctrl!=km->ctrl) return 0;
if(winevent->alt!=km->alt) return 0;
if(winevent->oskey!=km->oskey) return 0;
if(winevent->keymodifier!=km->keymodifier) return 0;
/* optional boundbox */
return 1;
}
static int wm_handler_operator_call(bContext *C, wmEventHandler *handler, wmEvent *event)
{
int retval= 0;
/* derived, modal or blocking operator */
if(handler->op) {
if( handler->op->type->poll(C)) {
if(handler->op->type->interactive)
retval= handler->op->type->interactive(C, handler->op, event);
else
printf("wm_handler_operator_call error\n");
}
}
else {
wmOperatorType *ot= WM_operatortype_find(event->keymap_idname);
if(ot) {
if(ot->poll(C)) {
/* operator on stack, register or new modal handle malloc-copies */
wmOperator op;
memset(&op, 0, sizeof(wmOperator));
op.type= ot;
if(op.type->interactive)
retval= op.type->interactive(C, &op, event);
else if(&op.type->exec)
retval= op.type->exec(C, &op);
if( ot->flag & OPTYPE_REGISTER)
WM_operator_register(C->wm, &op);
}
}
}
if(retval)
return WM_HANDLER_BREAK;
return WM_HANDLER_CONTINUE;
}
static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
{
wmEventHandler *handler;
int action= WM_HANDLER_CONTINUE;
if(handlers==NULL) return action;
for(handler= handlers->first; handler; handler= handler->next) {
if(handler->keymap) {
wmKeymapItem *km;
for(km= handler->keymap->first; km; km= km->next) {
if(wm_eventmatch(event, km)) {
if(event->type!=MOUSEMOVE)
printf("handle evt %d win %d op %s\n", event->type, C->window->winid, km->idname);
event->keymap_idname= km->idname; /* weak, but allows interactive callback to not use rawkey */
action= wm_handler_operator_call(C, handler, event);
}
}
if(action==WM_HANDLER_BREAK)
break;
}
/* modal+blocking handler */
if(handler->flag & WM_HANDLER_BLOCKING)
action= WM_HANDLER_BREAK;
}
return action;
}
static int wm_event_inside_i(wmEvent *event, rcti *rect)
{
return BLI_in_rcti(rect, event->x, event->y);
}
//static int wm_event_inside_f(wmEvent *event, rctf *rect)
//{
// return BLI_in_rctf(rect, (float)event->x, (float)event->y);
//}
/* called in main loop */
/* goes over entire hierarchy: events -> window -> screen -> area -> region */
void wm_event_do_handlers(bContext *C)
{
wmWindow *win;
for(win= C->wm->windows.first; win; win= win->next) {
wmEvent *event;
/* MVC demands to not draw in event handlers... for now we leave it */
/* it also updates context (win, screen) */
wm_window_make_drawable(C, win);
if( C->screen==NULL )
wm_event_free_all(C->window);
while( (event=wm_event_next(C->window)) ) {
int action= wm_handlers_do(C, event, &C->window->handlers);
if(action==WM_HANDLER_CONTINUE)
action= wm_handlers_do(C, event, &C->screen->handlers);
if(action==WM_HANDLER_CONTINUE) {
ScrArea *sa= C->screen->areabase.first;
for(; sa; sa= sa->next) {
if(wm_event_inside_i(event, &sa->winrct)) {
C->curarea= sa;
action= wm_handlers_do(C, event, &sa->handlers);
if(action==WM_HANDLER_CONTINUE) {
ARegion *ar= sa->regionbase.first;
for(; ar; ar= ar->next) {
if(wm_event_inside_i(event, &ar->winrct)) {
C->region= ar;
action= wm_handlers_do(C, event, &ar->handlers);
if(action==WM_HANDLER_BREAK)
break;
}
}
}
if(action==WM_HANDLER_BREAK)
break;
}
}
}
wm_event_free(event);
}
}
}
/* lets not expose struct outside wm? */
void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
{
handler->flag= flag;
}
wmEventHandler *WM_event_add_modal_keymap_handler(ListBase *keymap, ListBase *handlers, wmOperator *op)
{
/* debug test; operator not in registry */
if(op->type->flag & OPTYPE_REGISTER) {
printf("error: handler (%s) cannot be modal, was registered\n", op->type->idname);
}
else {
wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event handler");
wmOperator *opc= MEM_mallocN(sizeof(wmOperator), "operator modal");
BLI_addtail(handlers, handler);
handler->keymap= keymap;
*opc= *op;
handler->op= opc;
return handler;
}
return NULL;
}
wmEventHandler *WM_event_add_keymap_handler(ListBase *keymap, ListBase *handlers)
{
wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event handler");
BLI_addtail(handlers, handler);
handler->keymap= keymap;
return handler;
}
/* ********************* ghost stuff *************** */
static int convert_key(GHOST_TKey key)
{
if (key>=GHOST_kKeyA && key<=GHOST_kKeyZ) {
return (AKEY + ((int) key - GHOST_kKeyA));
} else if (key>=GHOST_kKey0 && key<=GHOST_kKey9) {
return (ZEROKEY + ((int) key - GHOST_kKey0));
} else if (key>=GHOST_kKeyNumpad0 && key<=GHOST_kKeyNumpad9) {
return (PAD0 + ((int) key - GHOST_kKeyNumpad0));
} else if (key>=GHOST_kKeyF1 && key<=GHOST_kKeyF12) {
return (F1KEY + ((int) key - GHOST_kKeyF1));
} else {
switch (key) {
case GHOST_kKeyBackSpace: return BACKSPACEKEY;
case GHOST_kKeyTab: return TABKEY;
case GHOST_kKeyLinefeed: return LINEFEEDKEY;
case GHOST_kKeyClear: return 0;
case GHOST_kKeyEnter: return RETKEY;
case GHOST_kKeyEsc: return ESCKEY;
case GHOST_kKeySpace: return SPACEKEY;
case GHOST_kKeyQuote: return QUOTEKEY;
case GHOST_kKeyComma: return COMMAKEY;
case GHOST_kKeyMinus: return MINUSKEY;
case GHOST_kKeyPeriod: return PERIODKEY;
case GHOST_kKeySlash: return SLASHKEY;
case GHOST_kKeySemicolon: return SEMICOLONKEY;
case GHOST_kKeyEqual: return EQUALKEY;
case GHOST_kKeyLeftBracket: return LEFTBRACKETKEY;
case GHOST_kKeyRightBracket: return RIGHTBRACKETKEY;
case GHOST_kKeyBackslash: return BACKSLASHKEY;
case GHOST_kKeyAccentGrave: return ACCENTGRAVEKEY;
case GHOST_kKeyLeftShift: return LEFTSHIFTKEY;
case GHOST_kKeyRightShift: return RIGHTSHIFTKEY;
case GHOST_kKeyLeftControl: return LEFTCTRLKEY;
case GHOST_kKeyRightControl: return RIGHTCTRLKEY;
case GHOST_kKeyCommand: return COMMANDKEY;
case GHOST_kKeyLeftAlt: return LEFTALTKEY;
case GHOST_kKeyRightAlt: return RIGHTALTKEY;
case GHOST_kKeyCapsLock: return CAPSLOCKKEY;
case GHOST_kKeyNumLock: return 0;
case GHOST_kKeyScrollLock: return 0;
case GHOST_kKeyLeftArrow: return LEFTARROWKEY;
case GHOST_kKeyRightArrow: return RIGHTARROWKEY;
case GHOST_kKeyUpArrow: return UPARROWKEY;
case GHOST_kKeyDownArrow: return DOWNARROWKEY;
case GHOST_kKeyPrintScreen: return 0;
case GHOST_kKeyPause: return PAUSEKEY;
case GHOST_kKeyInsert: return INSERTKEY;
case GHOST_kKeyDelete: return DELKEY;
case GHOST_kKeyHome: return HOMEKEY;
case GHOST_kKeyEnd: return ENDKEY;
case GHOST_kKeyUpPage: return PAGEUPKEY;
case GHOST_kKeyDownPage: return PAGEDOWNKEY;
case GHOST_kKeyNumpadPeriod: return PADPERIOD;
case GHOST_kKeyNumpadEnter: return PADENTER;
case GHOST_kKeyNumpadPlus: return PADPLUSKEY;
case GHOST_kKeyNumpadMinus: return PADMINUS;
case GHOST_kKeyNumpadAsterisk: return PADASTERKEY;
case GHOST_kKeyNumpadSlash: return PADSLASHKEY;
case GHOST_kKeyGrLess: return GRLESSKEY;
default:
return UNKNOWNKEY; /* GHOST_kKeyUnknown */
}
}
}
/* adds customdata to event */
static void update_tablet_data(wmWindow *win, wmEvent *event)
{
const GHOST_TabletData *td= GHOST_GetTabletData(win->ghostwin);
/* if there's tablet data from an active tablet device then add it */
if ((td != NULL) && td->Active) {
struct wmTabletData *wmtab= MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
wmtab->Active = td->Active;
wmtab->Pressure = td->Pressure;
wmtab->Xtilt = td->Xtilt;
wmtab->Ytilt = td->Ytilt;
event->custom= EVT_TABLET;
event->customdata= wmtab;
}
}
/* windows store own event queues, no bContext here */
void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata)
{
wmEvent event, *evt= win->eventstate;
/* initialize and copy state (only mouse x y and modifiers) */
event= *evt;
switch (type) {
/* mouse move */
case GHOST_kEventCursorMove: {
if(win->active) {
GHOST_TEventCursorData *cd= customdata;
int cx, cy;
GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy);
event.type= MOUSEMOVE;
event.x= evt->x= cx;
event.y= evt->y= (win->sizey-1) - cy;
update_tablet_data(win, &event);
wm_event_add(win, &event);
}
break;
}
/* mouse button */
case GHOST_kEventButtonDown:
case GHOST_kEventButtonUp: {
GHOST_TEventButtonData *bd= customdata;
event.val= (type==GHOST_kEventButtonDown);
if (bd->button == GHOST_kButtonMaskLeft)
event.type= LEFTMOUSE;
else if (bd->button == GHOST_kButtonMaskRight)
event.type= RIGHTMOUSE;
else
event.type= MIDDLEMOUSE;
update_tablet_data(win, &event);
wm_event_add(win, &event);
break;
}
/* keyboard */
case GHOST_kEventKeyDown:
case GHOST_kEventKeyUp: {
GHOST_TEventKeyData *kd= customdata;
event.type= convert_key(kd->key);
event.ascii= kd->ascii;
event.val= (type==GHOST_kEventKeyDown);
/* modifiers */
if (event.type==LEFTSHIFTKEY || event.type==RIGHTSHIFTKEY) {
event.shift= evt->shift= event.val;
} else if (event.type==LEFTCTRLKEY || event.type==RIGHTCTRLKEY) {
event.ctrl= evt->ctrl= event.val;
} else if (event.type==LEFTALTKEY || event.type==RIGHTALTKEY) {
event.alt= evt->alt= event.val;
} else if (event.type==COMMANDKEY) {
event.oskey= evt->oskey= event.val;
}
wm_event_add(win, &event);
break;
}
case GHOST_kEventWheel: {
GHOST_TEventWheelData* wheelData = customdata;
if (wheelData->z > 0)
event.type= WHEELUPMOUSE;
else
event.type= WHEELDOWNMOUSE;
event.val= wheelData->z; /* currently -1 or +1, see ghost for improvements here... */
wm_event_add(win, &event);
break;
}
case GHOST_kEventUnknown:
case GHOST_kNumEventTypes:
break;
}
}