1 /*
   2  * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.glass.ui.monocle.linux;
  27 
  28 import com.sun.glass.ui.monocle.input.InputDeviceRegistry;
  29 
  30 import java.io.File;
  31 import java.io.IOException;
  32 import java.security.AllPermission;
  33 import java.util.BitSet;
  34 import java.util.HashMap;
  35 import java.util.Map;
  36 
  37 public class LinuxInputDeviceRegistry extends InputDeviceRegistry {
  38 
  39     public LinuxInputDeviceRegistry(boolean headless) {
  40         if (headless) {
  41             // Keep the registry but do not bind it to udev.
  42             return;
  43         }
  44         Map<File, LinuxInputDevice> deviceMap = new HashMap<>();
  45         UdevListener udevListener = new UdevListener() {
  46             @Override
  47             public void udevEvent(String action, Map<String, String> event) {
  48                 String subsystem = event.get("SUBSYSTEM");
  49                 String devPath = event.get("DEVPATH");
  50                 String devName = event.get("DEVNAME");
  51                 if (subsystem != null && subsystem.equals("input")
  52                         && devPath != null && devName != null) {
  53                     try {
  54                         File sysPath = new File("/sys", devPath);
  55                         if (action.equals("add")
  56                                 || (action.equals("change")
  57                                 && !deviceMap.containsKey(sysPath))) {
  58                             File devNode = new File(devName);
  59                             LinuxInputDevice device = createDevice(
  60                                     devNode, sysPath, event);
  61                             if (device != null) {
  62                                 deviceMap.put(sysPath, device);
  63                             }
  64                         } else if (action.equals("remove")) {
  65                             LinuxInputDevice device = deviceMap.get(sysPath);
  66                             deviceMap.remove(sysPath);
  67                             if (device != null) {
  68                                 devices.remove(device);
  69                             }
  70                         }
  71                     } catch (IOException e) {
  72                         e.printStackTrace();
  73                     }
  74                 }
  75             }
  76         };
  77         Udev.getInstance().addListener(udevListener);
  78         // Request updates for existing devices
  79         SysFS.triggerUdevNotification("input");
  80     }
  81 
  82     private LinuxInputDevice createDevice(File devNode,
  83                                           File sysPath,
  84                                           Map<String, String> udevManifest)
  85             throws IOException {
  86         LinuxInputDevice device = new LinuxInputDevice(
  87                 devNode, sysPath, udevManifest);
  88         return addDeviceInternal(device, "Linux input: " + devNode.toString());
  89     }
  90 
  91     public LinuxInputDevice addDevice(LinuxInputDevice device, String name) {
  92         SecurityManager security = System.getSecurityManager();
  93         if (security != null) {
  94             security.checkPermission(new AllPermission());
  95         }
  96         return addDeviceInternal(device, name);
  97     }
  98 
  99     private LinuxInputDevice addDeviceInternal(LinuxInputDevice device, String name) {
 100         LinuxInputProcessor processor = createInputProcessor(device);
 101         if (processor == null) {
 102             return null;
 103         } else {
 104             device.setInputProcessor(createInputProcessor(device));
 105             Thread thread = new Thread(device);
 106             thread.setName(name);
 107             thread.setDaemon(true);
 108             thread.start();
 109             devices.add(device);
 110             return device;
 111         }
 112     }
 113 
 114     public void removeDevice(LinuxInputDevice device) {
 115         SecurityManager security = System.getSecurityManager();
 116         if (security != null) {
 117             security.checkPermission(new AllPermission());
 118         }
 119         devices.remove(device);
 120     }
 121 
 122     private LinuxInputProcessor createInputProcessor(LinuxInputDevice device) {
 123         if (device.isTouch()) {
 124             BitSet absCaps = device.getCapability("abs");
 125             boolean isMT = absCaps.get(Input.ABS_MT_POSITION_X)
 126                     && absCaps.get(Input.ABS_MT_POSITION_Y);
 127             if (isMT) {
 128                 if (absCaps.get(Input.ABS_MT_TRACKING_ID)) {
 129                     return new LinuxStatefulMultiTouchProcessor(device);
 130                 } else {
 131                     return new LinuxStatelessMultiTouchProcessor(device);
 132                 }
 133             } else {
 134                 return new LinuxSimpleTouchProcessor(device);
 135             }
 136         } else if (device.isRelative()) {
 137             return new LinuxMouseProcessor();
 138         } else {
 139             BitSet keyCaps = device.getCapability("key");
 140             if (keyCaps != null && !keyCaps.isEmpty()) {
 141                 return new LinuxKeyProcessor();
 142             } else {
 143                 return null;
 144             }
 145         }
 146     }
 147 
 148 }