sunMouse.c revision 9679a91b
1ee7c6486Stsutsui/* $Xorg: sunMouse.c,v 1.3 2000/08/17 19:48:32 cpqbld Exp $ */ 2ee7c6486Stsutsui/*- 3ee7c6486Stsutsui * Copyright 1987 by the Regents of the University of California 4ee7c6486Stsutsui * 5ee7c6486Stsutsui * Permission to use, copy, modify, and distribute this 6ee7c6486Stsutsui * software and its documentation for any purpose and without 7ee7c6486Stsutsui * fee is hereby granted, provided that the above copyright 8ee7c6486Stsutsui * notice appear in all copies. The University of California 9ee7c6486Stsutsui * makes no representations about the suitability of this 10ee7c6486Stsutsui * software for any purpose. It is provided "as is" without 11ee7c6486Stsutsui * express or implied warranty. 12ee7c6486Stsutsui */ 13ee7c6486Stsutsui 14ee7c6486Stsutsui/************************************************************ 15ee7c6486StsutsuiCopyright 1987 by Sun Microsystems, Inc. Mountain View, CA. 16ee7c6486Stsutsui 17ee7c6486Stsutsui All Rights Reserved 18ee7c6486Stsutsui 19ee7c6486StsutsuiPermission to use, copy, modify, and distribute this 20ee7c6486Stsutsuisoftware and its documentation for any purpose and without 21ee7c6486Stsutsuifee is hereby granted, provided that the above copyright no- 22ee7c6486Stsutsuitice appear in all copies and that both that copyright no- 23ee7c6486Stsutsuitice and this permission notice appear in supporting docu- 24ee7c6486Stsutsuimentation, and that the names of Sun or The Open Group 25ee7c6486Stsutsuinot be used in advertising or publicity pertaining to 26ee7c6486Stsutsuidistribution of the software without specific prior 27ee7c6486Stsutsuiwritten permission. Sun and The Open Group make no 28ee7c6486Stsutsuirepresentations about the suitability of this software for 29ee7c6486Stsutsuiany purpose. It is provided "as is" without any express or 30ee7c6486Stsutsuiimplied warranty. 31ee7c6486Stsutsui 32ee7c6486StsutsuiSUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 33ee7c6486StsutsuiINCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- 34ee7c6486StsutsuiNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- 35ee7c6486StsutsuiABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 36ee7c6486StsutsuiANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 37ee7c6486StsutsuiPROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 38ee7c6486StsutsuiOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH 39ee7c6486StsutsuiTHE USE OR PERFORMANCE OF THIS SOFTWARE. 40ee7c6486Stsutsui 41ee7c6486Stsutsui********************************************************/ 42ee7c6486Stsutsui/* 43ee7c6486Stsutsui * Copyright 1991, 1992, 1993 Kaleb S. Keithley 44ee7c6486Stsutsui * 45ee7c6486Stsutsui * Permission to use, copy, modify, and distribute this 46ee7c6486Stsutsui * software and its documentation for any purpose and without 47ee7c6486Stsutsui * fee is hereby granted, provided that the above copyright 48ee7c6486Stsutsui * notice appear in all copies. Kaleb S. Keithley makes no 49ee7c6486Stsutsui * representations about the suitability of this software for 50ee7c6486Stsutsui * any purpose. It is provided "as is" without express or 51ee7c6486Stsutsui * implied warranty. 52ee7c6486Stsutsui */ 53ee7c6486Stsutsui/* $XFree86: xc/programs/Xserver/hw/sun/sunMouse.c,v 1.4 2003/11/17 22:20:36 dawes Exp $ */ 54ee7c6486Stsutsui 55ee7c6486Stsutsui#define NEED_EVENTS 56ee7c6486Stsutsui#include "sun.h" 57ee7c6486Stsutsui#include "mi.h" 58ee7c6486Stsutsui#include "cursor.h" 59ee7c6486Stsutsui#include "input.h" 60ee7c6486Stsutsui#include "inpututils.h" 61ee7c6486Stsutsui#include "exevents.h" 62ee7c6486Stsutsui#include "xserver-properties.h" 63ee7c6486Stsutsui 64ee7c6486StsutsuiBool sunActiveZaphod = TRUE; 65ee7c6486StsutsuiDeviceIntPtr sunPointerDevice = NULL; 66ee7c6486Stsutsui 67ee7c6486Stsutsuistatic void sunMouseHandlerNotify(int, int, void *); 68ee7c6486Stsutsuistatic Bool sunCursorOffScreen(ScreenPtr *, int *, int *); 69ee7c6486Stsutsuistatic void sunCrossScreen(ScreenPtr, int); 70ee7c6486Stsutsuistatic void sunWarpCursor(DeviceIntPtr, ScreenPtr, int, int); 71ee7c6486Stsutsui 72ee7c6486StsutsuimiPointerScreenFuncRec sunPointerScreenFuncs = { 73ee7c6486Stsutsui sunCursorOffScreen, 74ee7c6486Stsutsui sunCrossScreen, 75ee7c6486Stsutsui sunWarpCursor, 76ee7c6486Stsutsui}; 77ee7c6486Stsutsui 78ee7c6486Stsutsuistatic void 79ee7c6486StsutsuisunMouseHandlerNotify(int fd __unused, int ready __unused, void *data __unused) 80ee7c6486Stsutsui{ 81ee7c6486Stsutsui} 82ee7c6486Stsutsui 83ee7c6486Stsutsui/*- 84ee7c6486Stsutsui *----------------------------------------------------------------------- 85ee7c6486Stsutsui * sunMouseCtrl -- 86ee7c6486Stsutsui * Alter the control parameters for the mouse. Since acceleration 87ee7c6486Stsutsui * etc. is done from the PtrCtrl record in the mouse's device record, 88ee7c6486Stsutsui * there's nothing to do here. 89ee7c6486Stsutsui * 90ee7c6486Stsutsui * Results: 91ee7c6486Stsutsui * None. 92ee7c6486Stsutsui * 93ee7c6486Stsutsui * Side Effects: 94ee7c6486Stsutsui * None. 95ee7c6486Stsutsui * 96ee7c6486Stsutsui *----------------------------------------------------------------------- 97ee7c6486Stsutsui */ 98ee7c6486Stsutsui/*ARGSUSED*/ 99ee7c6486Stsutsuistatic void 100ee7c6486StsutsuisunMouseCtrl(DeviceIntPtr device, PtrCtrl *ctrl) 101ee7c6486Stsutsui{ 102ee7c6486Stsutsui} 103ee7c6486Stsutsui 104ee7c6486Stsutsui/*- 105ee7c6486Stsutsui *----------------------------------------------------------------------- 106ee7c6486Stsutsui * sunMouseProc -- 107ee7c6486Stsutsui * Handle the initialization, etc. of a mouse 108ee7c6486Stsutsui * 109ee7c6486Stsutsui * Results: 110ee7c6486Stsutsui * none. 111ee7c6486Stsutsui * 112ee7c6486Stsutsui * Side Effects: 113ee7c6486Stsutsui * 114ee7c6486Stsutsui * Note: 115ee7c6486Stsutsui * When using sunwindows, all input comes off a single fd, stored in the 116ee7c6486Stsutsui * global windowFd. Therefore, only one device should be enabled and 117ee7c6486Stsutsui * disabled, even though the application still sees both mouse and 118ee7c6486Stsutsui * keyboard. We have arbitrarily chosen to enable and disable windowFd 119ee7c6486Stsutsui * in the keyboard routine sunKbdProc rather than in sunMouseProc. 120ee7c6486Stsutsui * 121ee7c6486Stsutsui *----------------------------------------------------------------------- 122ee7c6486Stsutsui */ 123ee7c6486Stsutsuiint 124ee7c6486StsutsuisunMouseProc(DeviceIntPtr device, int what) 125ee7c6486Stsutsui{ 1269679a91bStsutsui DevicePtr pMouse = &device->public; 127ee7c6486Stsutsui int format; 128ee7c6486Stsutsui static int oformat; 129ee7c6486Stsutsui BYTE map[4]; 130ee7c6486Stsutsui Atom btn_labels[3] = {0}; 131ee7c6486Stsutsui Atom axes_labels[2] = { 0, 0 }; 132ee7c6486Stsutsui 133ee7c6486Stsutsui switch (what) { 134ee7c6486Stsutsui case DEVICE_INIT: 1359679a91bStsutsui if (pMouse != &sunPointerDevice->public) { 136ee7c6486Stsutsui ErrorF ("Cannot open non-system mouse"); 137ee7c6486Stsutsui return !Success; 138ee7c6486Stsutsui } 139ee7c6486Stsutsui if (sunPtrPriv.fd == -1) 140ee7c6486Stsutsui return !Success; 141ee7c6486Stsutsui pMouse->devicePrivate = (void *) &sunPtrPriv; 142ee7c6486Stsutsui pMouse->on = FALSE; 143ee7c6486Stsutsui map[1] = 1; 144ee7c6486Stsutsui map[2] = 2; 145ee7c6486Stsutsui map[3] = 3; 146ee7c6486Stsutsui btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT); 147ee7c6486Stsutsui btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE); 148ee7c6486Stsutsui btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT); 149ee7c6486Stsutsui axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); 150ee7c6486Stsutsui axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y); 151ee7c6486Stsutsui 152ee7c6486Stsutsui InitPointerDeviceStruct(pMouse, map, 3, btn_labels, 153ee7c6486Stsutsui sunMouseCtrl, GetMotionHistorySize(), 154ee7c6486Stsutsui 2, axes_labels); 155ee7c6486Stsutsui break; 156ee7c6486Stsutsui 157ee7c6486Stsutsui case DEVICE_ON: 158ee7c6486Stsutsui if (ioctl (sunPtrPriv.fd, VUIDGFORMAT, &oformat) == -1) { 159ee7c6486Stsutsui ErrorF("sunMouseProc ioctl VUIDGFORMAT"); 160ee7c6486Stsutsui return !Success; 161ee7c6486Stsutsui } 162ee7c6486Stsutsui format = VUID_FIRM_EVENT; 163ee7c6486Stsutsui if (ioctl (sunPtrPriv.fd, VUIDSFORMAT, &format) == -1) { 164ee7c6486Stsutsui ErrorF("sunMouseProc ioctl VUIDSFORMAT"); 165ee7c6486Stsutsui return !Success; 166ee7c6486Stsutsui } 167ee7c6486Stsutsui sunPtrPriv.bmask = 0; 168ee7c6486Stsutsui SetNotifyFd(sunPtrPriv.fd, sunMouseHandlerNotify, 169ee7c6486Stsutsui X_NOTIFY_READ, NULL); 170ee7c6486Stsutsui pMouse->on = TRUE; 171ee7c6486Stsutsui break; 172ee7c6486Stsutsui 173ee7c6486Stsutsui case DEVICE_CLOSE: 174ee7c6486Stsutsui pMouse->on = FALSE; 175ee7c6486Stsutsui if (ioctl (sunPtrPriv.fd, VUIDSFORMAT, &oformat) == -1) 176ee7c6486Stsutsui ErrorF("sunMouseProc ioctl VUIDSFORMAT"); 177ee7c6486Stsutsui break; 178ee7c6486Stsutsui 179ee7c6486Stsutsui case DEVICE_OFF: 180ee7c6486Stsutsui pMouse->on = FALSE; 181ee7c6486Stsutsui RemoveNotifyFd(sunPtrPriv.fd); 182ee7c6486Stsutsui break; 183ee7c6486Stsutsui } 184ee7c6486Stsutsui return Success; 185ee7c6486Stsutsui} 186ee7c6486Stsutsui 187ee7c6486Stsutsui/*- 188ee7c6486Stsutsui *----------------------------------------------------------------------- 189ee7c6486Stsutsui * sunMouseGetEvents -- 190ee7c6486Stsutsui * Return the events waiting in the wings for the given mouse. 191ee7c6486Stsutsui * 192ee7c6486Stsutsui * Results: 193ee7c6486Stsutsui * A pointer to an array of Firm_events or (Firm_event *)0 if no events 194ee7c6486Stsutsui * The number of events contained in the array. 195ee7c6486Stsutsui * A boolean as to whether more events might be available. 196ee7c6486Stsutsui * 197ee7c6486Stsutsui * Side Effects: 198ee7c6486Stsutsui * None. 199ee7c6486Stsutsui *----------------------------------------------------------------------- 200ee7c6486Stsutsui */ 201ee7c6486Stsutsui 202ee7c6486StsutsuiFirm_event * 203ee7c6486StsutsuisunMouseGetEvents(int fd, Bool on, int *pNumEvents, Bool *pAgain) 204ee7c6486Stsutsui{ 205ee7c6486Stsutsui int nBytes; /* number of bytes of events available. */ 206ee7c6486Stsutsui static Firm_event evBuf[SUN_MAXEVENTS]; /* Buffer for Firm_events */ 207ee7c6486Stsutsui 208ee7c6486Stsutsui if ((nBytes = read (fd, (char *)evBuf, sizeof(evBuf))) == -1) { 209ee7c6486Stsutsui if (errno == EWOULDBLOCK) { 210ee7c6486Stsutsui *pNumEvents = 0; 211ee7c6486Stsutsui *pAgain = FALSE; 212ee7c6486Stsutsui } else { 213ee7c6486Stsutsui ErrorF("sunMouseGetEvents read"); 214ee7c6486Stsutsui FatalError ("Could not read from mouse"); 215ee7c6486Stsutsui } 216ee7c6486Stsutsui } else { 217ee7c6486Stsutsui if (on) { 218ee7c6486Stsutsui *pNumEvents = nBytes / sizeof (Firm_event); 219ee7c6486Stsutsui *pAgain = (nBytes == sizeof (evBuf)); 220ee7c6486Stsutsui } else { 221ee7c6486Stsutsui *pNumEvents = 0; 222ee7c6486Stsutsui *pAgain = FALSE; 223ee7c6486Stsutsui } 224ee7c6486Stsutsui } 225ee7c6486Stsutsui return evBuf; 226ee7c6486Stsutsui} 227ee7c6486Stsutsui 228ee7c6486Stsutsui 229ee7c6486Stsutsui/*- 230ee7c6486Stsutsui *----------------------------------------------------------------------- 231ee7c6486Stsutsui * sunMouseEnqueueEvent -- 232ee7c6486Stsutsui * Given a Firm_event for a mouse, pass it off the the dix layer 233ee7c6486Stsutsui * properly converted... 234ee7c6486Stsutsui * 235ee7c6486Stsutsui * Results: 236ee7c6486Stsutsui * None. 237ee7c6486Stsutsui * 238ee7c6486Stsutsui * Side Effects: 239ee7c6486Stsutsui * The cursor may be redrawn...? devPrivate/x/y will be altered. 240ee7c6486Stsutsui * 241ee7c6486Stsutsui *----------------------------------------------------------------------- 242ee7c6486Stsutsui */ 243ee7c6486Stsutsui 244ee7c6486Stsutsuivoid 245ee7c6486StsutsuisunMouseEnqueueEvent(DeviceIntPtr device, Firm_event *fe) 246ee7c6486Stsutsui{ 247ee7c6486Stsutsui sunPtrPrivPtr pPriv; /* Private data for pointer */ 248ee7c6486Stsutsui int bmask; /* Temporary button mask */ 249ee7c6486Stsutsui int x, y; 250ee7c6486Stsutsui double tmpx, tmpy; 251ee7c6486Stsutsui int type, buttons, flag; 252ee7c6486Stsutsui int valuators[2]; 253ee7c6486Stsutsui ValuatorMask mask; 254ee7c6486Stsutsui 255ee7c6486Stsutsui pPriv = (sunPtrPrivPtr)device->public.devicePrivate; 256ee7c6486Stsutsui 257ee7c6486Stsutsui switch (fe->id) { 258ee7c6486Stsutsui case MS_LEFT: 259ee7c6486Stsutsui case MS_MIDDLE: 260ee7c6486Stsutsui case MS_RIGHT: 261ee7c6486Stsutsui /* 262ee7c6486Stsutsui * A button changed state. Sometimes we will get two events 263ee7c6486Stsutsui * for a single state change. Should we get a button event which 264ee7c6486Stsutsui * reflects the current state of affairs, that event is discarded. 265ee7c6486Stsutsui * 266ee7c6486Stsutsui * Mouse buttons start at 1. 267ee7c6486Stsutsui */ 268ee7c6486Stsutsui buttons = (fe->id - MS_LEFT) + 1; 269ee7c6486Stsutsui bmask = 1 << buttons; 270ee7c6486Stsutsui if (fe->value == VKEY_UP) { 271ee7c6486Stsutsui if (pPriv->bmask & bmask) { 272ee7c6486Stsutsui type = ButtonRelease; 273ee7c6486Stsutsui pPriv->bmask &= ~bmask; 274ee7c6486Stsutsui } else { 275ee7c6486Stsutsui return; 276ee7c6486Stsutsui } 277ee7c6486Stsutsui } else { 278ee7c6486Stsutsui if ((pPriv->bmask & bmask) == 0) { 279ee7c6486Stsutsui type = ButtonPress; 280ee7c6486Stsutsui pPriv->bmask |= bmask; 281ee7c6486Stsutsui } else { 282ee7c6486Stsutsui return; 283ee7c6486Stsutsui } 284ee7c6486Stsutsui } 285ee7c6486Stsutsui flag = POINTER_RELATIVE; 286ee7c6486Stsutsui valuator_mask_set_range(&mask, 0, 0, NULL); 287ee7c6486Stsutsui QueuePointerEvents(device, type, buttons, flag, &mask); 288ee7c6486Stsutsui break; 289ee7c6486Stsutsui case LOC_X_DELTA: 290ee7c6486Stsutsui valuators[0] = fe->value; 291ee7c6486Stsutsui valuators[1] = 0; 292ee7c6486Stsutsui valuator_mask_set_range(&mask, 0, 2, valuators); 293ee7c6486Stsutsui flag = POINTER_RELATIVE | POINTER_ACCELERATE; 294ee7c6486Stsutsui QueuePointerEvents(device, MotionNotify, 0, flag, &mask); 295ee7c6486Stsutsui break; 296ee7c6486Stsutsui case LOC_Y_DELTA: 297ee7c6486Stsutsui /* 298ee7c6486Stsutsui * For some reason, motion up generates a positive y delta 299ee7c6486Stsutsui * and motion down a negative delta, so we must subtract 300ee7c6486Stsutsui * here instead of add... 301ee7c6486Stsutsui */ 302ee7c6486Stsutsui valuators[0] = 0; 303ee7c6486Stsutsui valuators[1] = -fe->value; 304ee7c6486Stsutsui valuator_mask_set_range(&mask, 0, 2, valuators); 305ee7c6486Stsutsui flag = POINTER_RELATIVE | POINTER_ACCELERATE; 306ee7c6486Stsutsui QueuePointerEvents(device, MotionNotify, 0, flag, &mask); 307ee7c6486Stsutsui break; 308ee7c6486Stsutsui case LOC_X_ABSOLUTE: 309ee7c6486Stsutsui miPointerGetPosition(device, &x, &y); 310ee7c6486Stsutsui tmpx = fe->value; 311ee7c6486Stsutsui tmpy = y; 312ee7c6486Stsutsui miPointerSetPosition(device, Absolute, &tmpx, &tmpy, NULL, NULL); 313ee7c6486Stsutsui break; 314ee7c6486Stsutsui case LOC_Y_ABSOLUTE: 315ee7c6486Stsutsui miPointerGetPosition(device, &x, &y); 316ee7c6486Stsutsui tmpx = x; 317ee7c6486Stsutsui tmpy = fe->value; 318ee7c6486Stsutsui miPointerSetPosition(device, Absolute, &tmpx, &tmpy, NULL, NULL); 319ee7c6486Stsutsui break; 320ee7c6486Stsutsui default: 321ee7c6486Stsutsui FatalError ("sunMouseEnqueueEvent: unrecognized id\n"); 322ee7c6486Stsutsui break; 323ee7c6486Stsutsui } 324ee7c6486Stsutsui} 325ee7c6486Stsutsui 326ee7c6486Stsutsui/*ARGSUSED*/ 327ee7c6486Stsutsuistatic Bool 328ee7c6486StsutsuisunCursorOffScreen(ScreenPtr *pScreen, int *x, int *y) 329ee7c6486Stsutsui{ 330ee7c6486Stsutsui int index, ret = FALSE; 331ee7c6486Stsutsui DeviceIntPtr device = sunPointerDevice; /* XXX */ 332ee7c6486Stsutsui 333ee7c6486Stsutsui if (device && PointerConfinedToScreen(device)) 334ee7c6486Stsutsui return TRUE; 335ee7c6486Stsutsui /* 336ee7c6486Stsutsui * Active Zaphod implementation: 337ee7c6486Stsutsui * increment or decrement the current screen 338ee7c6486Stsutsui * if the x is to the right or the left of 339ee7c6486Stsutsui * the current screen. 340ee7c6486Stsutsui */ 341ee7c6486Stsutsui if (sunActiveZaphod && 342ee7c6486Stsutsui screenInfo.numScreens > 1 && (*x >= (*pScreen)->width || *x < 0)) { 343ee7c6486Stsutsui index = (*pScreen)->myNum; 344ee7c6486Stsutsui if (*x < 0) { 345ee7c6486Stsutsui index = (index ? index : screenInfo.numScreens) - 1; 346ee7c6486Stsutsui *pScreen = screenInfo.screens[index]; 347ee7c6486Stsutsui *x += (*pScreen)->width; 348ee7c6486Stsutsui } else { 349ee7c6486Stsutsui *x -= (*pScreen)->width; 350ee7c6486Stsutsui index = (index + 1) % screenInfo.numScreens; 351ee7c6486Stsutsui *pScreen = screenInfo.screens[index]; 352ee7c6486Stsutsui } 353ee7c6486Stsutsui ret = TRUE; 354ee7c6486Stsutsui } 355ee7c6486Stsutsui return ret; 356ee7c6486Stsutsui} 357ee7c6486Stsutsui 358ee7c6486Stsutsuistatic void 359ee7c6486StsutsuisunCrossScreen(ScreenPtr pScreen, int entering) 360ee7c6486Stsutsui{ 361ee7c6486Stsutsui if (sunFbs[pScreen->myNum].EnterLeave) 362ee7c6486Stsutsui (*sunFbs[pScreen->myNum].EnterLeave) (pScreen, entering ? 0 : 1); 363ee7c6486Stsutsui} 364ee7c6486Stsutsui 365ee7c6486Stsutsuistatic void 366ee7c6486StsutsuisunWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) 367ee7c6486Stsutsui{ 368ee7c6486Stsutsui#ifndef i386 369ee7c6486Stsutsui sigset_t newsigmask; 370ee7c6486Stsutsui 371ee7c6486Stsutsui (void) sigemptyset (&newsigmask); 372ee7c6486Stsutsui#ifdef SVR4 373ee7c6486Stsutsui (void) sigaddset (&newsigmask, SIGPOLL); 374ee7c6486Stsutsui#else 375ee7c6486Stsutsui (void) sigaddset (&newsigmask, SIGIO); 376ee7c6486Stsutsui#endif 377ee7c6486Stsutsui (void) sigprocmask (SIG_BLOCK, &newsigmask, NULL); 378ee7c6486Stsutsui miPointerWarpCursor (pDev, pScreen, x, y); 379ee7c6486Stsutsui (void) sigprocmask (SIG_UNBLOCK, &newsigmask, NULL); 380ee7c6486Stsutsui#else 381ee7c6486Stsutsui int oldmask; 382ee7c6486Stsutsui 383ee7c6486Stsutsui oldmask = sigblock (sigmask (SIGIO)); 384ee7c6486Stsutsui miPointerWarpCursor (pDev, pScreen, x, y); 385ee7c6486Stsutsui sigsetmask (oldmask); 386ee7c6486Stsutsui#endif 387ee7c6486Stsutsui} 388