1265N/A/* Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
764N/A *
764N/A * Permission is hereby granted, free of charge, to any person obtaining a
919N/A * copy of this software and associated documentation files (the "Software"),
919N/A * to deal in the Software without restriction, including without limitation
919N/A * the rights to use, copy, modify, merge, publish, distribute, sublicense,
919N/A * and/or sell copies of the Software, and to permit persons to whom the
919N/A * Software is furnished to do so, subject to the following conditions:
764N/A *
919N/A * The above copyright notice and this permission notice (including the next
919N/A * paragraph) shall be included in all copies or substantial portions of the
919N/A * Software.
764N/A *
919N/A * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
919N/A * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
919N/A * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
919N/A * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
919N/A * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
919N/A * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
919N/A * DEALINGS IN THE SOFTWARE.
764N/A */
764N/A
764N/A
764N/A#include "config.h"
1124N/A#include <xorg-server.h>
1124N/A
764N/A#include "xf86.h"
764N/A#include "xf86Priv.h"
764N/A#include "xf86Xinput.h"
764N/A#include "xf86_OSproc.h"
764N/A#include <X11/XF86keysym.h>
764N/A#include <unistd.h>
764N/A#include <sys/stat.h>
764N/A#include <signal.h>
764N/A#include <errno.h>
764N/A#include <libsysevent.h>
764N/A#include <xkbsrv.h>
764N/A
1124N/Astatic int HkeyPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags);
764N/Astatic void HkeyUnInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags);
764N/A
764N/A_X_EXPORT InputDriverRec HKEY = {
764N/A 1,
764N/A "hotkey",
764N/A NULL,
764N/A HkeyPreInit,
764N/A HkeyUnInit,
764N/A NULL,
764N/A 0
764N/A};
764N/A
764N/Astatic struct {
764N/A const char *sub_class;
764N/A KeySym keysym;
764N/A} sub_to_keysym_table [] = {
764N/A { "ESC_acpiev_display_switch", XF86XK_Display },
764N/A { "ESC_acpiev_sleep", XF86XK_Sleep },
764N/A { "ESC_acpiev_screen_lock", XF86XK_ScreenSaver },
764N/A { NULL, NoSymbol }
764N/A};
764N/A
764N/A
764N/A#define EC_ACPIEV "EC_acpiev"
764N/A#define HOTKEY_KEYSYM_ROOT (XF86XK_Display & 0xFFFFFF00)
764N/A
764N/Astatic sysevent_handle_t *hotkey_event_entry;
764N/Astatic int hotkey_event_fd[2] = {-1, -1};
764N/A
764N/Astatic void
764N/Ahotkey_event_handler(sysevent_t *ev)
764N/A{
764N/A int i;
764N/A char buf;
764N/A char *subclass;
764N/A KeySym keysym = 0;
764N/A
764N/A subclass = sysevent_get_subclass_name(ev);
764N/A for (i = 0; sub_to_keysym_table[i].sub_class != NULL; i++)
764N/A if (!strcmp (sub_to_keysym_table[i].sub_class, subclass)) {
764N/A keysym = sub_to_keysym_table[i].keysym;
764N/A break;
764N/A }
764N/A
764N/A if (sub_to_keysym_table[i].sub_class == NULL)
764N/A return;
764N/A
764N/A buf = keysym - HOTKEY_KEYSYM_ROOT;
764N/A
764N/A write(hotkey_event_fd[1], &buf, 1);
764N/A}
764N/A
764N/A
764N/Astatic Bool
764N/Amap_init(DeviceIntPtr device)
764N/A{
764N/A
764N/A#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 5
893N/A if (!InitKeyboardDeviceStruct(device, NULL, NULL, NULL)) {
764N/A xf86Msg(X_WARNING, "hotkey map_init failed\n");
764N/A return FALSE;
764N/A }
764N/A#else
764N/A KeySymsRec keySyms;
764N/A CARD8 *modMap;
764N/A
764N/A keySyms.minKeyCode = inputInfo.keyboard->key->curKeySyms.minKeyCode;
764N/A keySyms.maxKeyCode = inputInfo.keyboard->key->curKeySyms.maxKeyCode;
764N/A keySyms.mapWidth = inputInfo.keyboard->key->curKeySyms.mapWidth;
764N/A
764N/A keySyms.map = (KeySym *)xcalloc(sizeof(KeySym),
764N/A (keySyms.maxKeyCode - keySyms.minKeyCode + 1) * keySyms.mapWidth);
764N/A if (!keySyms.map) {
764N/A xf86Msg (X_WARNING, "Couldn't allocate hotkey core keymap\n");
764N/A return FALSE;
764N/A }
764N/A
764N/A modMap = (CARD8 *)xcalloc(1, MAP_LENGTH);
764N/A if (!modMap) {
764N/A xf86Msg (X_WARNING, "Couldn't allocate hotkey modifier keymap\n");
764N/A return FALSE;
764N/A }
764N/A
764N/A#ifdef XKB
764N/A if (!noXkbExtension) {
764N/A XkbComponentNamesRec names;
764N/A
764N/A bzero(&names, sizeof(names));
764N/A XkbInitKeyboardDeviceStruct(device, &names, &keySyms, modMap, NULL, NULL);
764N/A } else
764N/A#endif
764N/A /* FIXME Our keymap here isn't exactly useful. */
764N/A InitKeyboardDeviceStruct((DevicePtr)device, &keySyms, modMap, NULL, NULL);
764N/A
764N/A xfree(keySyms.map);
764N/A xfree(modMap);
764N/A#endif
764N/A
764N/A return TRUE;
764N/A}
764N/A
764N/Astatic void
764N/Ahotkey_events_fini(void)
764N/A{
764N/A sysevent_unsubscribe_event (hotkey_event_entry, EC_ACPIEV);
764N/A sysevent_unbind_handle (hotkey_event_entry);
764N/A hotkey_event_entry = NULL;
764N/A xf86Msg(X_CONFIG, "hotkey_events_fini: succeeded\n");
764N/A}
764N/A
764N/Astatic Bool
764N/Ahotkey_events_init(DeviceIntPtr device) {
764N/A const char *subclass_list[] = {EC_SUB_ALL};
764N/A
764N/A hotkey_event_entry = sysevent_bind_handle (hotkey_event_handler);
764N/A if (hotkey_event_entry == NULL) {
764N/A xf86Msg(X_WARNING,
764N/A "hotkey_events_init: sysevent_bind_handle failed: with errno = %d\n" , errno);
764N/A return FALSE;
764N/A }
764N/A else {
764N/A if (sysevent_subscribe_event(hotkey_event_entry, EC_ACPIEV, subclass_list, 1)
764N/A != 0) {
764N/A sysevent_unbind_handle(hotkey_event_entry);
764N/A hotkey_event_entry = NULL;
764N/A xf86Msg(X_CONFIG, "hotkey_events_init: sysevent_subscribe_event failed\n");
764N/A return FALSE;
764N/A }
764N/A }
764N/A
764N/A return TRUE;
764N/A}
764N/A
764N/Astatic void
764N/Ahotkey_read_input(InputInfoPtr pInfo)
764N/A{
764N/A unsigned char buf;
764N/A KeySym keysym = NoSymbol;
764N/A KeyCode keycode = 0;
764N/A KeySymsPtr curKeySyms;
764N/A DeviceIntPtr dev = pInfo->dev;
764N/A int i;
764N/A
764N/A if (read (pInfo->fd, &buf, 1 ) == 1)
764N/A keysym = buf + HOTKEY_KEYSYM_ROOT;
764N/A
851N/A#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 5
1265N/A if (dev->master)
1265N/A curKeySyms = XkbGetCoreMap(dev->master);
893N/A else
893N/A curKeySyms = XkbGetCoreMap(inputInfo.keyboard);
851N/A#else
1265N/A if (dev->master)
1265N/A curKeySyms = &dev->master->key->curKeySyms;
764N/A else
764N/A curKeySyms = &inputInfo.keyboard->key->curKeySyms;
851N/A#endif
764N/A
764N/A for (i = curKeySyms->minKeyCode; i <= curKeySyms->maxKeyCode; i++) {
764N/A if (curKeySyms->map[(i - curKeySyms->minKeyCode) * curKeySyms->mapWidth]
764N/A == keysym) {
764N/A keycode = i;
764N/A break;
764N/A }
764N/A }
764N/A
764N/A if (!keycode)
764N/A xf86MsgVerb(X_WARNING, 0, "Hotkey keysym %x not mapped\n", (int) keysym);
764N/A else {
764N/A xf86MsgVerb(X_INFO, 3, "Posting keycode %d for keysym %x on device %s\n",
764N/A keycode, (int) keysym, pInfo->dev->name);
764N/A xf86PostKeyboardEvent(pInfo->dev, keycode, TRUE);
764N/A xf86PostKeyboardEvent(pInfo->dev, keycode, FALSE);
764N/A }
764N/A}
764N/A
764N/Astatic int
764N/AHkeyProc(DeviceIntPtr device, int what)
764N/A{
764N/A InputInfoPtr pInfo = device->public.devicePrivate;
764N/A char *s;
764N/A DeviceIntPtr mdev;
782N/A int blocked;
764N/A
764N/A switch (what) {
764N/A case DEVICE_INIT:
764N/A if (!map_init(device)) {
764N/A xf86Msg(X_WARNING, "HkeyProc: map_init failed\n");
764N/A return (!Success);
764N/A }
764N/A
782N/A /*
782N/A * Block SIGIO so the new libsysevent/door threads created will
782N/A * mask SIGIO. See 6875743.
782N/A */
782N/A blocked = xf86BlockSIGIO();
782N/A
764N/A if (hotkey_events_init(device)) {
764N/A if (pipe (hotkey_event_fd) == -1) {
764N/A xf86Msg(X_WARNING,
764N/A "hotkey_events_init: pipe open failed with errno %d\n", errno);
764N/A hotkey_events_fini();
782N/A xf86UnblockSIGIO(blocked);
764N/A return (!Success);
764N/A } else {
764N/A pInfo->fd = hotkey_event_fd[0];
764N/A xf86Msg(X_CONFIG, "hotkey_events_init and pipe open succeeded\n");
764N/A }
764N/A } else {
764N/A xf86Msg(X_WARNING, "hotkey_events_init failed\n");
782N/A xf86UnblockSIGIO(blocked);
764N/A return (!Success);
764N/A }
764N/A
782N/A xf86UnblockSIGIO(blocked);
782N/A
764N/A device->public.on = FALSE;
764N/A break;
764N/A case DEVICE_ON:
764N/A if (device->public.on)
764N/A break;
764N/A xf86FlushInput(pInfo->fd);
764N/A AddEnabledDevice(pInfo->fd);
764N/A
1265N/A if (device->master)
1265N/A dixSetPrivate(&device->master->devPrivates,
764N/A HotkeyMapDevicePrivateKey, device);
764N/A
764N/A device->public.on = TRUE;
764N/A break;
764N/A case DEVICE_CLOSE:
764N/A if (pInfo->fd != -1)
764N/A RemoveEnabledDevice(pInfo->fd);
764N/A close(hotkey_event_fd[0]);
764N/A close(hotkey_event_fd[1]);
764N/A hotkey_events_fini();
764N/A break;
764N/A case DEVICE_OFF:
764N/A if (!device->public.on)
764N/A break;
764N/A if (pInfo->fd != -1)
764N/A RemoveEnabledDevice(pInfo->fd);
764N/A
1265N/A if (device->master)
1265N/A dixSetPrivate(&device->master->devPrivates,
764N/A HotkeyMapDevicePrivateKey, NULL);
764N/A
764N/A device->public.on = FALSE;
764N/A break;
764N/A }
764N/A
764N/A return (Success);
764N/A}
764N/A
1124N/Astatic int
1124N/AHkeyPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
764N/A{
764N/A /* Initialize the InputInfoRec. */
764N/A pInfo->type_name = XI_KEYBOARD;
764N/A pInfo->device_control = HkeyProc;
764N/A pInfo->read_input = hotkey_read_input;
764N/A pInfo->fd = -1;
1124N/A pInfo->flags = XI86_ALWAYS_CORE;
764N/A
1124N/A return Success;
764N/A}
764N/A
764N/Astatic void
764N/AHkeyUnInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
764N/A{
764N/A xf86DeleteInput(pInfo, 0);
764N/A}
764N/A
764N/Astatic void
764N/AHkeyUnplug(pointer p)
764N/A{
764N/A}
764N/A
764N/Astatic pointer
764N/AHkeyPlug(pointer module, pointer options, int *errmaj, int *errmin)
764N/A{
764N/A static Bool Initialised = FALSE;
764N/A
764N/A if (!Initialised)
764N/A Initialised = TRUE;
764N/A
764N/A xf86AddInputDriver(&HKEY, module, 0);
764N/A
764N/A return module;
764N/A}
764N/A
764N/A
764N/Astatic XF86ModuleVersionInfo HkeyVersionRec = {
764N/A "hotkey",
764N/A MODULEVENDORSTRING,
764N/A MODINFOSTRING1,
764N/A MODINFOSTRING2,
764N/A XORG_VERSION_CURRENT,
764N/A 1, 0, 0,
764N/A ABI_CLASS_XINPUT,
764N/A ABI_XINPUT_VERSION,
764N/A MOD_CLASS_XINPUT,
764N/A {0, 0, 0, 0} /* signature, to be patched into the file by */
764N/A /* a tool */
764N/A};
764N/A
764N/A_X_EXPORT XF86ModuleData hotkeyModuleData = {
764N/A &HkeyVersionRec,
764N/A HkeyPlug,
764N/A HkeyUnplug
764N/A};
764N/A